chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
file(
|
||||
GLOB TEST_OPS
|
||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"test_*.py")
|
||||
string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}")
|
||||
set(SOT_ENVS SOT_LOG_LEVEL=0 MIN_GRAPH_SIZE=0 STRICT_MODE=True
|
||||
SOT_ENABLE_STRICT_GUARD_CHECK=True FLAGS_cudnn_deterministic=True)
|
||||
|
||||
foreach(TEST_OP ${TEST_OPS})
|
||||
py_test_modules(${TEST_OP} MODULES ${TEST_OP} ENVS ${SOT_ENVS})
|
||||
endforeach()
|
||||
|
||||
if(WIN32)
|
||||
set_tests_properties(test_sot_resnet50_backward PROPERTIES TIMEOUT 420)
|
||||
set_tests_properties(test_sot_resnet PROPERTIES TIMEOUT 200)
|
||||
endif()
|
||||
@@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def foo(x: int, y: paddle.Tensor):
|
||||
return x + y
|
||||
|
||||
|
||||
class TestBasic(TestCaseBase):
|
||||
def test_simple(self):
|
||||
self.assert_results(foo, 1, paddle.to_tensor(2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
|
||||
# Instructions:
|
||||
# LOAD_FAST
|
||||
# BINARY_ADD
|
||||
# RETURN_VALUE
|
||||
|
||||
# Variables:
|
||||
# ConstantVariable
|
||||
# TensorVariable
|
||||
@@ -0,0 +1,47 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def foo(x: int, y: paddle.Tensor):
|
||||
x = x + 1
|
||||
y = y + 1
|
||||
x += y
|
||||
return x
|
||||
|
||||
|
||||
class TestStoreInplace(TestCaseBase):
|
||||
def test_simple(self):
|
||||
self.assert_results(foo, 1, paddle.to_tensor(2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
|
||||
# Instructions:
|
||||
# LOAD_FAST
|
||||
# BINARY_ADD
|
||||
# STORE_FAST (new)
|
||||
# INPLACE_ADD (new)
|
||||
# RETURN_VALUE
|
||||
|
||||
# Variables:
|
||||
# ConstantVariable
|
||||
# TensorVariable
|
||||
@@ -0,0 +1,127 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# New Supported Instructions:
|
||||
# BUILD_TUPLE
|
||||
# BINARY_SUBSCR
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils import with_control_flow_guard
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def build_tuple(x: int, y: paddle.Tensor):
|
||||
x = (x, y)
|
||||
return x[1] + 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def build_tuple_with_slice_subscript(x: int, y: paddle.Tensor):
|
||||
z = (x, y, 3, 4)
|
||||
return z[0:5:1]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def build_tuple_with_int_subscript(x: int, y: paddle.Tensor):
|
||||
z = (x, y)
|
||||
return z[0]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tuple_count_int(x: int, y: paddle.Tensor):
|
||||
z = (x, x, 2, 1)
|
||||
return z.count(x)
|
||||
|
||||
|
||||
def tuple_count_tensor(x: paddle.Tensor, y: tuple[paddle.Tensor]):
|
||||
return y.count(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tuple_index_int(x: int, y: paddle.Tensor):
|
||||
z = (x, y, x, y, y)
|
||||
return z.index(x)
|
||||
|
||||
|
||||
def tuple_index_tensor(x: paddle.Tensor, y: tuple[paddle.Tensor]):
|
||||
return y.index(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tuple_compare():
|
||||
# TODO(SigureMo): support gt, ge, lt, le
|
||||
l1 = (1, 2, 3)
|
||||
l2 = (1, 2, 3)
|
||||
l3 = (1, 2, 4)
|
||||
return l1 == l2, l1 == l3, l1 != l2, l1 != l3
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tuple_add():
|
||||
l0 = (1, 2, 3)
|
||||
l1 = (4, 5, 6)
|
||||
return l0 + l1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tuple_inplace_add():
|
||||
l0 = (1, 2, 3)
|
||||
l1 = l0
|
||||
l2 = (4, 5, 6)
|
||||
l0 += l2
|
||||
return l0, l1
|
||||
|
||||
|
||||
class TestBuildTuple(TestCaseBase):
|
||||
def test_build_tuple(self):
|
||||
self.assert_results(build_tuple, 1, paddle.to_tensor(2))
|
||||
self.assert_results(
|
||||
build_tuple_with_slice_subscript, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results(
|
||||
build_tuple_with_int_subscript, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
|
||||
class TestTupleMethods(TestCaseBase):
|
||||
def test_tuple_methods_int(self):
|
||||
self.assert_results(tuple_count_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results(tuple_index_int, 1, paddle.to_tensor(2))
|
||||
|
||||
@with_control_flow_guard(False)
|
||||
def test_tuple_methods_tensor(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
self.assert_results(tuple_count_tensor, a, (a, b, a, b))
|
||||
self.assert_results(tuple_index_tensor, b, (b, b, b, a))
|
||||
|
||||
def test_tuple_compare(self):
|
||||
self.assert_results(tuple_compare)
|
||||
|
||||
def test_tuple_add(self):
|
||||
self.assert_results(tuple_add)
|
||||
|
||||
def test_tuple_inplace_add(self):
|
||||
self.assert_results(tuple_inplace_add)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,379 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# New Supported Instructions:
|
||||
# BUILD_LIST (new)
|
||||
# BINARY_SUBSCR
|
||||
# DELETE_SUBSCR
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_getitem_int(x: int, y: paddle.Tensor):
|
||||
x = [x, y]
|
||||
return x[0] + 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_getitem_tensor(x: int, y: paddle.Tensor):
|
||||
x = [x, y]
|
||||
return x[1] + 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_setitem_int(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
z[0] = 3
|
||||
return z
|
||||
|
||||
|
||||
def list_setitem_tensor(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
z[1] = paddle.to_tensor(3)
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_delitem_int(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
del z[0]
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_delitem_tensor(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
del z[1]
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_construct_from_list(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_append_int(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
z.append(3)
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_append_tensor(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
z.append(y)
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_clear(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
z.clear()
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_copy(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
a = z.copy()
|
||||
z[0] = 3
|
||||
z[1] = y + 1
|
||||
return (a, z)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_count_int(x: int, y: paddle.Tensor):
|
||||
z = [x, x, 2, 3, 1]
|
||||
return z.count(x)
|
||||
|
||||
|
||||
def list_count_tensor(x: paddle.Tensor, y: list[paddle.Tensor]):
|
||||
return y.count(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_extend(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
a = [y, x]
|
||||
b = (x, y)
|
||||
z.extend(a)
|
||||
z.extend(b)
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_index_int(x: int, y: paddle.Tensor):
|
||||
z = [x, x, 1, 2]
|
||||
return z.index(x)
|
||||
|
||||
|
||||
def list_index_tensor(x: paddle.Tensor, y: list[paddle.Tensor]):
|
||||
return y.index(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_insert(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
z.insert(0, x)
|
||||
z.insert(3, y)
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_pop(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
a = z.pop()
|
||||
b = z.pop()
|
||||
return (z, a, b)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_remove(x: int, y: paddle.Tensor):
|
||||
z = [x, x, y, y]
|
||||
z.remove(x)
|
||||
z.remove(y)
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_reverse(x: int, y: paddle.Tensor):
|
||||
z = [x, x, y, y]
|
||||
z.reverse()
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_default_sort(x: int, y: paddle.Tensor):
|
||||
z = [x + 2, x, x + 1]
|
||||
z.sort()
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_key_sort(x: int, y: paddle.Tensor):
|
||||
z = [x + 2, x, x + 1]
|
||||
z.sort(lambda x: x)
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_reverse_sort(x: int, y: paddle.Tensor):
|
||||
z = [x + 2, x, x + 1]
|
||||
z.sort(reverse=True)
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_tensor_sort(x: int, y: paddle.Tensor):
|
||||
z = [y + 2, y, y + 1]
|
||||
z.sort()
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_max(x: paddle.Tensor | int, y: paddle.Tensor | int):
|
||||
z = [x, x, y]
|
||||
return max(z)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_tensor_max_api(x: paddle.Tensor):
|
||||
return x.max()
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_min(x: paddle.Tensor | int, y: paddle.Tensor | int):
|
||||
z = [x, x, y]
|
||||
return min(z)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_tensor_min_api(x: paddle.Tensor):
|
||||
return x.min()
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_no_arguments():
|
||||
l1 = list() # noqa: C408
|
||||
l1.append(1)
|
||||
l2 = list() # noqa: C408
|
||||
l2.append(2)
|
||||
return l1[0] + l2[0]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_compare():
|
||||
# TODO(SigureMo): support gt, ge, lt, le
|
||||
l1 = [1, 2, 3]
|
||||
l2 = [1, 2, 3]
|
||||
l3 = [1, 2, 4]
|
||||
return l1 == l2, l1 == l3, l1 != l2, l1 != l3
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_add():
|
||||
l0 = [1, 2, 3]
|
||||
l1 = [4, 5, 6]
|
||||
return l0 + l1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_inplace_add():
|
||||
l0 = [1, 2, 3]
|
||||
l1 = l0
|
||||
l2 = [4, 5, 6]
|
||||
l0 += l2
|
||||
return l0, l1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_extend_range(x):
|
||||
return [1, *range(0, len(x.shape))]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_extend_dict():
|
||||
l1 = []
|
||||
l1.extend({1: 2, 2: 3, 3: 4})
|
||||
return l1
|
||||
|
||||
|
||||
class TestListBasic(TestCaseBase):
|
||||
def test_list_basic(self):
|
||||
self.assert_results(list_getitem_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results(list_getitem_tensor, 1, paddle.to_tensor(2))
|
||||
self.assert_results_with_side_effects(
|
||||
list_setitem_int, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
|
||||
class TestListMethods(TestCaseBase):
|
||||
def test_list_setitem(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_setitem_tensor, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_list_count_and_index(self):
|
||||
self.assert_results(list_count_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results(list_index_int, 1, paddle.to_tensor(2))
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
self.assert_results(list_count_tensor, a, [a, b, a, b, a, b])
|
||||
self.assert_results(list_index_tensor, b, [a, b, a, b, a, b])
|
||||
|
||||
def test_list_delitem(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_delitem_int, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
list_delitem_tensor, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_list_append(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_append_int, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
list_append_tensor, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_list_clear(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_clear, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_list_copy(self):
|
||||
self.assert_results_with_side_effects(list_copy, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_list_extend(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_extend, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_list_insert(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_insert, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_list_pop(self):
|
||||
self.assert_results_with_side_effects(list_pop, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_list_remove(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_remove, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_list_reverse(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_reverse, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
list_reverse, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_list_sort(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_default_sort, 1, paddle.to_tensor(2)
|
||||
)
|
||||
# TODO: Not currently supported
|
||||
# self.assert_results_with_side_effects(
|
||||
# list_tensor_sort, 1, paddle.to_tensor(2)
|
||||
# )
|
||||
# self.assert_results_with_side_effects(
|
||||
# list_key_sort, 1, paddle.to_tensor(2)
|
||||
# )
|
||||
# self.assert_results_with_side_effects(
|
||||
# list_reverse_sort, 1, paddle.to_tensor(2)
|
||||
# )
|
||||
|
||||
def test_list_construct_from_list(self):
|
||||
self.assert_results(list_construct_from_list, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_list_max_min(self):
|
||||
self.assert_results(list_max, 1, 2)
|
||||
self.assert_results(list_min, 1, 2)
|
||||
self.assert_results(list_tensor_max_api, paddle.to_tensor([1, 2, 3]))
|
||||
self.assert_results(list_tensor_min_api, paddle.to_tensor([1, 2, 3]))
|
||||
|
||||
def test_list_noargs(self):
|
||||
self.assert_results(list_no_arguments)
|
||||
|
||||
def test_list_compare(self):
|
||||
self.assert_results(list_compare)
|
||||
|
||||
def test_list_add(self):
|
||||
self.assert_results(list_add)
|
||||
|
||||
def test_list_inplace_add(self):
|
||||
self.assert_results(list_inplace_add)
|
||||
|
||||
def test_list_extend_range(self):
|
||||
self.assert_results(list_extend_range, paddle.to_tensor([1, 2]))
|
||||
|
||||
def test_list_extend_dict(self):
|
||||
self.assert_results(list_extend_dict)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,325 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# New Supported Instructions:
|
||||
# BUILD_MAP (new)
|
||||
# BUILD_CONST_KEY_MAP (new)
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def build_map(x: int, y: paddle.Tensor):
|
||||
z = {x: y}
|
||||
return z[x] + 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def build_const_key_map(x: int, y: paddle.Tensor):
|
||||
z = {1: y, 2: y + 1}
|
||||
return z[x] + 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_get_item(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
return (z.get(1), z.get(2))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_get_item_default(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
return (z.get(3, 2), z.get(4, y))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_set_item_int(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
z[1] = x * 2
|
||||
return z[1]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_set_item_tensor(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
z[2] = y
|
||||
return z[1]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_update_item1(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
z.update({1: x * 2, 2: y, 3: y + 2})
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_update_item2(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
z.update({1: x * 2, 2: y, 3: z[2] + 2})
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_del_item_int(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
del z[1]
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_del_item_tensor(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
del z[2]
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_clear(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
z.clear()
|
||||
return z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_copy(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
z2 = z.copy()
|
||||
z[1] = 2
|
||||
return z2
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_setdefault_int(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
a = z.setdefault(4)
|
||||
b = z.setdefault(1, 2)
|
||||
c = z.setdefault(3, 4)
|
||||
return (z, a, b, c)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_pop(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1, 3: y}
|
||||
a = z.pop(1)
|
||||
b = z.pop(2, 3)
|
||||
c = z.pop(4, 3)
|
||||
d = z.pop(5, y)
|
||||
return (z, a, b, c, d)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_popitem(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1, 3: y}
|
||||
a = z.popitem()
|
||||
return (z, a)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_construct_from_dict():
|
||||
x = {1: 2, 3: 4}
|
||||
d = dict(x)
|
||||
return d
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_construct_from_list():
|
||||
x = [[1, 2], [3, 4]]
|
||||
d = dict(x)
|
||||
return d
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_construct_from_tuple():
|
||||
x = ((1, 2), (3, 4))
|
||||
d = dict(x)
|
||||
return d
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_construct_from_comprehension():
|
||||
z = {1: 2, 3: 4}
|
||||
d = {k: v + 1 for k, v in z.items()}
|
||||
return d
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_no_arguments():
|
||||
d1 = dict() # noqa: C408
|
||||
d1.update({1: 2})
|
||||
d2 = dict() # noqa: C408
|
||||
d2.update({3: 4})
|
||||
return d1[1] + d2[3]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_test_fromkeys(x):
|
||||
d = dict.fromkeys(x)
|
||||
return d
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_test_fromkeys_default(x, y):
|
||||
d = dict.fromkeys(x, y)
|
||||
return d
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_keyword_init():
|
||||
d = dict(x=1, y=2) # noqa: C408
|
||||
return d["x"] + d["y"]
|
||||
|
||||
|
||||
@strict_mode_guard(False)
|
||||
@check_no_breakgraph
|
||||
def raise_keyerror_with_number(x):
|
||||
x += 1
|
||||
a = {}
|
||||
a[8]
|
||||
x /= 3
|
||||
|
||||
|
||||
@strict_mode_guard(False)
|
||||
@check_no_breakgraph
|
||||
def raise_keyerror_with_str(x):
|
||||
x += 1
|
||||
a = {}
|
||||
a["8"]
|
||||
x /= 3
|
||||
|
||||
|
||||
class TestDict:
|
||||
def __init__(self, data) -> None:
|
||||
self.data = data
|
||||
|
||||
def __getitem__(self, key):
|
||||
try:
|
||||
return self.data[key]
|
||||
except KeyError:
|
||||
raise
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def raise_keyerror_with_custom_obj(x):
|
||||
x += 1
|
||||
data = TestDict({})
|
||||
try:
|
||||
x *= 3
|
||||
data['a']
|
||||
x -= 3
|
||||
except KeyError:
|
||||
x /= 3
|
||||
return x
|
||||
|
||||
|
||||
class TestBuildDict(TestCaseBase):
|
||||
def test_build_map(self):
|
||||
self.assert_results(build_map, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_build_const_key_map(self):
|
||||
self.assert_results(build_const_key_map, 1, paddle.to_tensor(2))
|
||||
|
||||
|
||||
class TestDictMethods(TestCaseBase):
|
||||
def test_dict_get_item(self):
|
||||
self.assert_results(dict_get_item, 1, paddle.to_tensor(2))
|
||||
self.assert_results(dict_get_item_default, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_dict_set_item(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_set_item_int, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
dict_set_item_tensor, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_dict_copy(self):
|
||||
self.assert_results_with_side_effects(dict_copy, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_dict_update(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_update_item1, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
dict_update_item2, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_dict_setdefault(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_setdefault_int, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_dict_del_item(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_del_item_int, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
dict_del_item_tensor, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_dict_clear(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_clear, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_dict_pop(self):
|
||||
self.assert_results_with_side_effects(dict_pop, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_dict_popitem(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_popitem, 1, paddle.to_tensor(2)
|
||||
)
|
||||
|
||||
def test_construct(self):
|
||||
self.assert_results(dict_construct_from_dict)
|
||||
self.assert_results(dict_construct_from_list)
|
||||
self.assert_results(dict_construct_from_tuple)
|
||||
self.assert_results(dict_construct_from_comprehension)
|
||||
|
||||
def test_dict_noargs(self):
|
||||
self.assert_results(dict_no_arguments)
|
||||
|
||||
def test_dict_fromkeys(self):
|
||||
self.assert_results(dict_test_fromkeys, (1, 2, 3, 4))
|
||||
self.assert_results(dict_test_fromkeys, [1, 2, 3, 4])
|
||||
self.assert_results(dict_test_fromkeys_default, (1, 2, 3, 4), 1)
|
||||
self.assert_results(
|
||||
dict_test_fromkeys_default, (1, 2, 3, 4), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(dict_test_fromkeys_default, [1, 2, 3, 4], 1)
|
||||
self.assert_results(
|
||||
dict_test_fromkeys_default, [1, 2, 3, 4], paddle.to_tensor(1)
|
||||
)
|
||||
|
||||
def test_dict_keyword_init(self):
|
||||
self.assert_results(dict_keyword_init)
|
||||
|
||||
|
||||
class TestDictKeyError(TestCaseBase):
|
||||
def test_dict_keyerror(self):
|
||||
with self.assertRaisesRegex(KeyError, "^8$"):
|
||||
self.assert_results(raise_keyerror_with_number, paddle.to_tensor(5))
|
||||
with self.assertRaisesRegex(KeyError, "^'8'$"):
|
||||
self.assert_results(raise_keyerror_with_str, paddle.to_tensor(5))
|
||||
self.assert_results(raise_keyerror_with_custom_obj, paddle.ones([3]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,221 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
|
||||
def sub(x, y):
|
||||
return x - y
|
||||
|
||||
|
||||
def foo_1(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
y = add(m * 3, m * 2)
|
||||
return y
|
||||
|
||||
|
||||
def foo_2(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
y = sub(m * 3, m * 2)
|
||||
return y
|
||||
|
||||
|
||||
def foo_3(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
y = sub(m * 3, m * 2)
|
||||
y = sub(y, y)
|
||||
y = sub(y, y)
|
||||
return y
|
||||
|
||||
|
||||
def nest_2(x):
|
||||
return x + 1
|
||||
|
||||
|
||||
def nest_1(x):
|
||||
return (x - 1) * 2
|
||||
|
||||
|
||||
def foo_4(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
m = nest_1(m)
|
||||
return m
|
||||
|
||||
|
||||
def fn_with_varargs_and_kwargs(x, *args, **kwargs):
|
||||
return (
|
||||
x
|
||||
+ args[0]
|
||||
+ args[1]
|
||||
- args[2]
|
||||
+ kwargs['a'] * kwargs['b']
|
||||
+ kwargs['c']
|
||||
)
|
||||
|
||||
|
||||
def foo_5(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
m = fn_with_varargs_and_kwargs(
|
||||
m, x + 1, x + 2, x + 3, a=x + 4, b=x + 5, c=x + 6
|
||||
)
|
||||
return m
|
||||
|
||||
|
||||
def fn_with_default_value(x, y=1, z=2):
|
||||
return x + y + z
|
||||
|
||||
|
||||
def foo_6(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
m = fn_with_default_value(m, m + 10)
|
||||
m = fn_with_default_value(m + 42)
|
||||
return m
|
||||
|
||||
|
||||
def fn_with_default_value_and_varargs_kwargs(x, y=1, *args, **kwargs):
|
||||
return x + y + args[0] + kwargs['a']
|
||||
|
||||
|
||||
def foo_7(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
m = fn_with_default_value_and_varargs_kwargs(m, m + 1, m + 2, a=m + 3)
|
||||
return m
|
||||
|
||||
|
||||
def fn_with_default_value_and_varargs_kwargs_kwonly_1(
|
||||
x, y=1, *args, z, **kwargs
|
||||
):
|
||||
return x + y + args[0] + kwargs['a'] + z
|
||||
|
||||
|
||||
def fn_with_default_value_and_varargs_kwargs_kwonly_2(
|
||||
x, y=1, *args, z=10, **kwargs
|
||||
):
|
||||
return x + y + args[0] + kwargs['a'] + z
|
||||
|
||||
|
||||
def foo_8(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
m = fn_with_default_value_and_varargs_kwargs_kwonly_1(
|
||||
m, m + 1, m + 2, a=m + 3, z=m + 4
|
||||
)
|
||||
m = fn_with_default_value_and_varargs_kwargs_kwonly_2(
|
||||
m, m + 1, m + 2, a=m + 3
|
||||
)
|
||||
return m
|
||||
|
||||
|
||||
class TestCall(TestCaseBase):
|
||||
def test_call1(self):
|
||||
self.assert_results(foo_1, paddle.to_tensor(2))
|
||||
|
||||
def test_call2(self):
|
||||
self.assert_results(foo_2, paddle.to_tensor(3))
|
||||
|
||||
def test_call3(self):
|
||||
self.assert_results(foo_3, paddle.to_tensor(4))
|
||||
|
||||
def test_call4(self):
|
||||
self.assert_results(foo_4, paddle.to_tensor(5))
|
||||
|
||||
def test_call5(self):
|
||||
self.assert_results(foo_5, paddle.to_tensor(6))
|
||||
|
||||
def test_call6(self):
|
||||
self.assert_results(foo_6, paddle.to_tensor(7))
|
||||
|
||||
def test_call7(self):
|
||||
self.assert_results(foo_7, paddle.to_tensor(8))
|
||||
|
||||
def test_call8(self):
|
||||
self.assert_results(foo_8, paddle.to_tensor(9))
|
||||
|
||||
|
||||
def apply_fn(fn, x):
|
||||
return fn(x)
|
||||
|
||||
|
||||
def fn1(x):
|
||||
return x + 1
|
||||
|
||||
|
||||
def fn2(x):
|
||||
return x - 1
|
||||
|
||||
|
||||
class TestApplyDifferentFunctions(TestCaseBase):
|
||||
def test_apply_fn(self):
|
||||
x = 1
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(apply_fn, fn1, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(apply_fn, fn2, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(apply_fn, fn1, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def positional_only_basic(x, /, y):
|
||||
z = x + y
|
||||
return x + z
|
||||
|
||||
|
||||
def positional_only_breakgraph(x, /, y):
|
||||
z = x + y
|
||||
paddle.jit.sot.psdb.breakgraph()
|
||||
return x + z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def keyword_only_basic(x, *, y):
|
||||
z = x + y
|
||||
return x + z
|
||||
|
||||
|
||||
def keyword_only_breakgraph(x, *, y):
|
||||
z = x + y
|
||||
paddle.jit.sot.psdb.breakgraph()
|
||||
return x + z
|
||||
|
||||
|
||||
class TestPositionalKeywordOnly(TestCaseBase):
|
||||
def test_positional_only_basic(self):
|
||||
self.assert_results(positional_only_basic, 1, 2)
|
||||
|
||||
def test_positional_only_breakgraph(self):
|
||||
self.assert_results(positional_only_breakgraph, 1, 2)
|
||||
|
||||
def test_keyword_only_basic(self):
|
||||
self.assert_results(keyword_only_basic, x=1, y=2)
|
||||
|
||||
def test_keyword_only_breakgraph(self):
|
||||
self.assert_results(keyword_only_breakgraph, x=1, y=2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,70 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# New Supported Instructions:
|
||||
# UNPACK_SEQUENCE (new)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def unpack_tuple(x: tuple[int, paddle.Tensor]):
|
||||
y, z = x
|
||||
return z + 1
|
||||
|
||||
|
||||
def unpack_tensor(x: paddle.Tensor):
|
||||
a, b = x
|
||||
return (a, b)
|
||||
|
||||
|
||||
def unpack_ex_tuple(x: tuple[int, int, paddle.Tensor]):
|
||||
*y, z = x
|
||||
return z + 1
|
||||
|
||||
|
||||
def unpack_ex_tensor(x: paddle.Tensor):
|
||||
a, b, *c = x
|
||||
return (a, b)
|
||||
|
||||
|
||||
def unpack_ex_tensor_2(x: paddle.Tensor):
|
||||
a, *b, c, d = x
|
||||
return (a, c)
|
||||
|
||||
|
||||
class TestUnpack(TestCaseBase):
|
||||
def test_unpack_tuple(self):
|
||||
self.assert_results(unpack_tuple, (1, paddle.to_tensor(2)))
|
||||
|
||||
def test_unpack_tensor(self):
|
||||
self.assert_results(unpack_tensor, paddle.to_tensor([2, 3]))
|
||||
|
||||
def test_unpack_ex_tuple(self):
|
||||
self.assert_results(unpack_ex_tuple, (1, 1, paddle.to_tensor(2)))
|
||||
|
||||
def test_unpack_ex_tensor(self):
|
||||
self.assert_results(unpack_ex_tensor, paddle.to_tensor([2, 3, 3, 3]))
|
||||
|
||||
def test_unpack_ex_tensor_2(self):
|
||||
self.assert_results(unpack_ex_tensor_2, paddle.to_tensor([2, 3, 3, 3]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,97 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def rot_two_return_a(a: paddle.Tensor, b: paddle.Tensor):
|
||||
b, a = a, b
|
||||
return a + 1
|
||||
|
||||
|
||||
def rot_two_return_b(a: paddle.Tensor, b: paddle.Tensor):
|
||||
b, a = a, b
|
||||
return b + 2
|
||||
|
||||
|
||||
def rot_three_return_a(a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor):
|
||||
a, b, c = c, b, a
|
||||
return a + 1
|
||||
|
||||
|
||||
def rot_three_return_b(a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor):
|
||||
a, b, c = c, b, a
|
||||
return b + 1
|
||||
|
||||
|
||||
def rot_three_return_c(a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor):
|
||||
a, b, c = c, b, a
|
||||
return c + 1
|
||||
|
||||
|
||||
def rot_four_return_a(
|
||||
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
|
||||
):
|
||||
a, b, c, d = d, c, b, a
|
||||
return a + 1
|
||||
|
||||
|
||||
def rot_four_return_b(
|
||||
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
|
||||
):
|
||||
a, b, c, d = d, c, b, a
|
||||
return b + 1
|
||||
|
||||
|
||||
def rot_four_return_c(
|
||||
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
|
||||
):
|
||||
a, b, c, d = d, c, b, a
|
||||
return c + 1
|
||||
|
||||
|
||||
def rot_four_return_d(
|
||||
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
|
||||
):
|
||||
a, b, c, d = d, c, b, a
|
||||
return d + 1
|
||||
|
||||
|
||||
class TestRot(TestCaseBase):
|
||||
def test_simple(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
c = paddle.to_tensor(3)
|
||||
d = paddle.to_tensor(4)
|
||||
self.assert_results(rot_two_return_a, a, b)
|
||||
self.assert_results(rot_two_return_b, a, b)
|
||||
|
||||
self.assert_results(rot_three_return_a, a, b, c)
|
||||
self.assert_results(rot_three_return_b, a, b, c)
|
||||
self.assert_results(rot_three_return_c, a, b, c)
|
||||
|
||||
self.assert_results(rot_four_return_a, a, b, c, d)
|
||||
self.assert_results(rot_four_return_b, a, b, c, d)
|
||||
self.assert_results(rot_four_return_c, a, b, c, d)
|
||||
self.assert_results(rot_four_return_d, a, b, c, d)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,64 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# FORMAT_VALUE (new)
|
||||
# BUILD_STRING (new)
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import assert_true
|
||||
|
||||
|
||||
def foo(x: paddle.Tensor):
|
||||
whilespace = 123
|
||||
hello_world = f"Hello {whilespace} World"
|
||||
z = assert_true(hello_world == "Hello 123 World")
|
||||
x = x + 1
|
||||
return x
|
||||
|
||||
|
||||
def fstring_with_convert_test(x: paddle.Tensor):
|
||||
obj = 42
|
||||
formatted_string = f"{obj!r}"
|
||||
z = assert_true(formatted_string == "42")
|
||||
x = x + 1
|
||||
return x
|
||||
|
||||
|
||||
def fstring_with_spec(x: paddle.Tensor):
|
||||
int_num = 42
|
||||
float_num = 3.1415
|
||||
formatted_string = f"{int_num} and {float_num:.2f}"
|
||||
z = assert_true(formatted_string == "42 and 3.14")
|
||||
x = x + 1
|
||||
return x
|
||||
|
||||
|
||||
class TestFString(TestCaseBase):
|
||||
def test_f_string(self):
|
||||
self.assert_results(foo, paddle.to_tensor(1))
|
||||
|
||||
def test_f_string_with_spec(self):
|
||||
self.assert_results(fstring_with_spec, paddle.to_tensor(1))
|
||||
|
||||
def test_f_string_with_convert_test(self):
|
||||
self.assert_results(fstring_with_convert_test, paddle.to_tensor(1))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,97 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# BUILD_TUPLE_UNPACK (new)
|
||||
# BUILD_LIST_UNPACK (new)
|
||||
# BUILD_TUPLE_UNPACK_WITH_CALL (new)
|
||||
# CALL_FUNCTION_EX (new)
|
||||
# BUILD_MAP_UNPACK (new)
|
||||
# LIST_EXTEND (new)
|
||||
# LIST_TO_TUPLE (new)
|
||||
# DICT_UPDATE (new)
|
||||
# DICT_MERGE (new)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def build_tuple_unpack(x: tuple[paddle.Tensor], y: tuple[paddle.Tensor]):
|
||||
z = (*x, *y)
|
||||
|
||||
return z[0] + 1
|
||||
|
||||
|
||||
def build_list_unpack(x: list[paddle.Tensor], y: list[paddle.Tensor]):
|
||||
z = [*x, *y]
|
||||
return z[0] + 1
|
||||
|
||||
|
||||
def build_tuple_unpack_with_call(
|
||||
x: tuple[paddle.Tensor], y: tuple[paddle.Tensor]
|
||||
):
|
||||
z = build_tuple_unpack_with_call_inner(*x, *y)
|
||||
return z[0] + 1
|
||||
|
||||
|
||||
def build_tuple_unpack_with_call_inner(
|
||||
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
|
||||
):
|
||||
z = (a, b, c, d)
|
||||
return z
|
||||
|
||||
|
||||
def build_map_unpack(x: dict[str, paddle.Tensor], y: dict[str, paddle.Tensor]):
|
||||
z = {**x, **y}
|
||||
return z["a"] + 1
|
||||
|
||||
|
||||
def build_map_unpack_with_call_inner(
|
||||
a: paddle.Tensor, b: paddle.Tensor, c: paddle.Tensor, d: paddle.Tensor
|
||||
):
|
||||
z = {"a": a, "b": b, "c": c, "d": d}
|
||||
return z
|
||||
|
||||
|
||||
def build_map_unpack_with_call(
|
||||
x: dict[str, paddle.Tensor], y: dict[str, paddle.Tensor]
|
||||
):
|
||||
z = build_map_unpack_with_call_inner(**x, **y)
|
||||
return z["a"] + 1
|
||||
|
||||
|
||||
class TestBuildUnpack(TestCaseBase):
|
||||
def test_simple(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
c = paddle.to_tensor(3)
|
||||
d = paddle.to_tensor(4)
|
||||
|
||||
self.assert_results(build_tuple_unpack, (a, b), (c, d))
|
||||
self.assert_results(build_list_unpack, [a, b], [c, d])
|
||||
self.assert_results(build_tuple_unpack_with_call, (a, b), (c, d))
|
||||
self.assert_results(
|
||||
build_map_unpack, {"a": a, "b": b}, {"c": c, "d": d}
|
||||
)
|
||||
self.assert_results(
|
||||
build_map_unpack_with_call, {"a": a, "b": b}, {"c": c, "d": d}
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,125 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
def pop_jump_if_false(x: bool, y: paddle.Tensor):
|
||||
if x:
|
||||
y += 1
|
||||
else:
|
||||
y -= 1
|
||||
return y
|
||||
|
||||
|
||||
def pop_jump_if_true(x: bool, y: bool, z: paddle.Tensor):
|
||||
return (x or y) and z
|
||||
|
||||
|
||||
def jump_if_false_or_pop(x: bool, y: paddle.Tensor):
|
||||
return x and (y + 1)
|
||||
|
||||
|
||||
def jump_if_true_or_pop(x: bool, y: paddle.Tensor):
|
||||
return x or (y + 1)
|
||||
|
||||
|
||||
def jump_absolute(x: int, y: paddle.Tensor):
|
||||
while x > 0:
|
||||
y += 1
|
||||
x -= 1
|
||||
return y
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def pop_jump_if_none(x: bool, y: paddle.Tensor):
|
||||
if x is not None:
|
||||
y += 1
|
||||
else:
|
||||
y -= 1
|
||||
return y
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def pop_jump_if_not_none(x: bool, y: paddle.Tensor):
|
||||
if x is None:
|
||||
y += 1
|
||||
else:
|
||||
y -= 1
|
||||
return y
|
||||
|
||||
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
c = paddle.to_tensor(3)
|
||||
d = paddle.to_tensor(4)
|
||||
|
||||
true_tensor = paddle.to_tensor(True)
|
||||
false_tensor = paddle.to_tensor(False)
|
||||
|
||||
|
||||
class TestJump(TestCaseBase):
|
||||
def test_simple(self):
|
||||
self.assert_results(jump_absolute, 5, a)
|
||||
|
||||
self.assert_results(pop_jump_if_false, True, a)
|
||||
self.assert_results(pop_jump_if_false, False, a)
|
||||
self.assert_results(jump_if_false_or_pop, True, a)
|
||||
self.assert_results(jump_if_false_or_pop, False, a)
|
||||
self.assert_results(jump_if_true_or_pop, True, a)
|
||||
self.assert_results(jump_if_true_or_pop, False, a)
|
||||
self.assert_results(pop_jump_if_true, True, False, a)
|
||||
self.assert_results(pop_jump_if_true, False, False, a)
|
||||
|
||||
self.assert_results(pop_jump_if_none, None, a)
|
||||
self.assert_results(pop_jump_if_none, True, a)
|
||||
self.assert_results(pop_jump_if_not_none, None, a)
|
||||
self.assert_results(pop_jump_if_not_none, True, a)
|
||||
|
||||
def test_breakgraph(self):
|
||||
self.assert_results(pop_jump_if_false, true_tensor, a)
|
||||
self.assert_results(jump_if_false_or_pop, true_tensor, a)
|
||||
self.assert_results(jump_if_true_or_pop, false_tensor, a)
|
||||
self.assert_results(pop_jump_if_true, true_tensor, false_tensor, a)
|
||||
self.assert_results(jump_absolute, 5, a)
|
||||
self.assert_results(pop_jump_if_false, false_tensor, a)
|
||||
self.assert_results(jump_if_false_or_pop, false_tensor, a)
|
||||
self.assert_results(jump_if_true_or_pop, false_tensor, a)
|
||||
self.assert_results(pop_jump_if_true, true_tensor, false_tensor, a)
|
||||
|
||||
self.assert_results(pop_jump_if_none, true_tensor, a)
|
||||
self.assert_results(pop_jump_if_not_none, true_tensor, a)
|
||||
|
||||
|
||||
def new_var_in_if():
|
||||
x = paddle.to_tensor(1)
|
||||
if x > 0:
|
||||
y = 1
|
||||
return y
|
||||
|
||||
|
||||
class TestCreateVarInIf(TestCaseBase):
|
||||
def test_case(self):
|
||||
self.assert_results(new_var_in_if)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,363 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# GET_ITER (new)
|
||||
# FOR_ITER (new)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
def gener():
|
||||
yield 1
|
||||
yield 2
|
||||
yield 3
|
||||
|
||||
|
||||
def for_list_1(x: paddle.Tensor):
|
||||
for i in [1, 2, 3]:
|
||||
x += i
|
||||
|
||||
if x > 2:
|
||||
x += 1
|
||||
else:
|
||||
x -= 1
|
||||
return x
|
||||
|
||||
|
||||
def for_list_2(x: paddle.Tensor):
|
||||
for i in [1, 2, 3]:
|
||||
x += i
|
||||
|
||||
if i > 2:
|
||||
x += 1
|
||||
else:
|
||||
x -= 1
|
||||
return x
|
||||
|
||||
|
||||
def for_dict(x: paddle.Tensor):
|
||||
map = {1: 2, 3: 4}
|
||||
for k in map.keys():
|
||||
x += k
|
||||
|
||||
for v in map.values():
|
||||
x += v
|
||||
|
||||
for k, v in map.items():
|
||||
x += k
|
||||
x += v
|
||||
|
||||
return x
|
||||
|
||||
|
||||
def for_iter(x, it):
|
||||
for item in it:
|
||||
x += item
|
||||
return x
|
||||
|
||||
|
||||
def for_for_fallback(x, it):
|
||||
for i in [1, 2, 3]:
|
||||
for item in it:
|
||||
x += item
|
||||
return x
|
||||
|
||||
|
||||
def for_break(x: paddle.Tensor, it):
|
||||
for i in [1, 2, 3]:
|
||||
x += i
|
||||
if i == 2:
|
||||
break
|
||||
for i in it:
|
||||
x += i
|
||||
if i == 2:
|
||||
break
|
||||
return x
|
||||
|
||||
|
||||
def for_continue(x: paddle.Tensor, it):
|
||||
for i in [1, 2, 3]:
|
||||
if i == 2:
|
||||
continue
|
||||
x += i
|
||||
|
||||
for i in it:
|
||||
if i == 2:
|
||||
continue
|
||||
x += i
|
||||
return x
|
||||
|
||||
|
||||
def for_enumerate_var_with_nested_range(x_array):
|
||||
x = paddle.tensor.fill_constant([1], 'int32', 0)
|
||||
x_array = paddle.to_tensor(x_array)
|
||||
for i, num in enumerate(x_array):
|
||||
for idx in range(num):
|
||||
x = x + num
|
||||
return x
|
||||
|
||||
|
||||
def for_create_tmp_in_loop(x, it):
|
||||
s = x
|
||||
for i in it:
|
||||
tmp = i
|
||||
s += tmp
|
||||
return s, tmp
|
||||
|
||||
|
||||
def for_without_zero_iter(self_res_dict, output):
|
||||
res_dict = {"logits": output}
|
||||
for res_key in list(self_res_dict):
|
||||
res_dict[res_key] = self_res_dict.pop(res_key)
|
||||
return res_dict
|
||||
|
||||
|
||||
def for_reconstruct_range_iter():
|
||||
for i in range(3):
|
||||
sot.psdb.breakgraph()
|
||||
|
||||
|
||||
global_var_name = None
|
||||
|
||||
|
||||
def for_tmp_var_with_same_name_as_global_var():
|
||||
total = 0
|
||||
for i in range(3):
|
||||
global_var_name = i + 3
|
||||
sot.psdb.breakgraph()
|
||||
total += global_var_name
|
||||
return total
|
||||
|
||||
|
||||
def for_layer_list(layer_list, x):
|
||||
for net in layer_list:
|
||||
x = net(x)
|
||||
return x
|
||||
|
||||
|
||||
class TestForLoop(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_list(self):
|
||||
a = paddle.to_tensor(1)
|
||||
self.assert_results(for_list_1, a)
|
||||
|
||||
def test_list_with_fallback(self):
|
||||
a = paddle.to_tensor(1)
|
||||
self.assert_results(for_list_2, a)
|
||||
|
||||
def test_dict(self):
|
||||
a = paddle.to_tensor(1)
|
||||
self.assert_results(for_dict, a)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_fallback(self):
|
||||
a = paddle.to_tensor(1)
|
||||
|
||||
sym_output = symbolic_translate(for_iter)(a, gener())
|
||||
paddle_output = for_iter(a, gener())
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_for_iter_fallback(self):
|
||||
a = paddle.to_tensor(1)
|
||||
|
||||
sym_output = symbolic_translate(for_iter)(a, gener())
|
||||
paddle_output = for_iter(a, gener())
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_for_break(self):
|
||||
a = paddle.to_tensor(1)
|
||||
sym_output = symbolic_translate(for_break)(a, gener())
|
||||
paddle_output = for_break(a, gener())
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_for_continue(self):
|
||||
a = paddle.to_tensor(1)
|
||||
sym_output = symbolic_translate(for_continue)(a, gener())
|
||||
paddle_output = for_continue(a, gener())
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_create_var_in_loop(self):
|
||||
x = paddle.to_tensor(1, dtype="float32")
|
||||
a = [1, 2, 3]
|
||||
self.assert_results(for_create_tmp_in_loop, x, a)
|
||||
|
||||
sym_output = symbolic_translate(for_create_tmp_in_loop)(x, iter(a))
|
||||
paddle_output = for_create_tmp_in_loop(x, iter(a))
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_create_var_in_loop_with_same_name_as_global(self):
|
||||
self.assert_results(for_tmp_var_with_same_name_as_global_var)
|
||||
|
||||
def test_for_without_zero_iter(self):
|
||||
self_res_dict = {}
|
||||
output = paddle.to_tensor(2)
|
||||
self.assert_results(for_without_zero_iter, self_res_dict, output)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_reconstruct_range_iter(self):
|
||||
self.assert_results(for_reconstruct_range_iter)
|
||||
|
||||
def test_layer_list(self):
|
||||
layers = paddle.nn.LayerList()
|
||||
for i in range(5):
|
||||
layers.append(paddle.nn.Linear(5, 5))
|
||||
x = paddle.rand([5], dtype="float32")
|
||||
self.assert_results(for_layer_list, layers, x)
|
||||
|
||||
|
||||
def run_list_comp(x):
|
||||
out = [s.chunk(2, axis=1) for s in x]
|
||||
return out
|
||||
|
||||
|
||||
class TestListComp(TestCaseBase):
|
||||
def test_list_comp(self):
|
||||
x = [paddle.randn([1, 4]), paddle.randn([1, 4])]
|
||||
self.assert_results(run_list_comp, x)
|
||||
|
||||
|
||||
def for_enumerate_cache(func_list, x):
|
||||
out = None
|
||||
for idx, func in enumerate(func_list):
|
||||
out = func(x[idx])
|
||||
return out
|
||||
|
||||
|
||||
class TestEnumerateCache(TestCaseBase):
|
||||
def test_run(self):
|
||||
func_list = [
|
||||
paddle.nn.Linear(10, 10),
|
||||
]
|
||||
x = [
|
||||
paddle.randn([5, 10]),
|
||||
]
|
||||
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
out = symbolic_translate(for_enumerate_cache)(func_list, x)
|
||||
out = symbolic_translate(for_enumerate_cache)(func_list, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
|
||||
# after_loop_fn need zzz, and zzz is created as UndefinedVar when generating loop body
|
||||
# do not set zzz as UndefinedVar again
|
||||
def undefined_var_case_0():
|
||||
for i in [1, 2]:
|
||||
sot.psdb.breakgraph()
|
||||
zzz = i
|
||||
|
||||
zzz = zzz + 1
|
||||
return zzz
|
||||
|
||||
|
||||
# after_loop_fn need create zzz as UndefinedVar
|
||||
def undefined_var_case_1():
|
||||
for i in [1, 2]:
|
||||
sot.psdb.breakgraph()
|
||||
aaa = i
|
||||
|
||||
for i in [1, 3]:
|
||||
zzz = i
|
||||
zzz = zzz + 1
|
||||
return zzz
|
||||
|
||||
|
||||
class TestUndefinedVarInRiskyCodes(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_undefined_var_case_0(self):
|
||||
self.assert_results(undefined_var_case_0)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_undefined_var_case_1(self):
|
||||
self.assert_results(undefined_var_case_1)
|
||||
|
||||
|
||||
def comp_with_fallback(x):
|
||||
paddle.jit.sot.psdb.fallback()
|
||||
y = [len(t) for t in x]
|
||||
return paddle.to_tensor(y)
|
||||
|
||||
|
||||
class TestListCompWithFallback(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_list_comp_with_fallback(self):
|
||||
x = [paddle.randn([4, 6])]
|
||||
self.assert_results(comp_with_fallback, x)
|
||||
|
||||
|
||||
def for_arange(x):
|
||||
for i in paddle.arange(0, 5):
|
||||
x = x + i
|
||||
return x
|
||||
|
||||
|
||||
class TestArange(TestCaseBase):
|
||||
def test_arange(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(for_arange, x)
|
||||
|
||||
|
||||
def for_break_with_load_same_consts(x: paddle.Tensor):
|
||||
y = None
|
||||
z = None
|
||||
for i in [1, 2, 3]:
|
||||
if y is None:
|
||||
y = i
|
||||
if z is None:
|
||||
z = i
|
||||
x += y + z
|
||||
sot.psdb.breakgraph()
|
||||
return x
|
||||
|
||||
|
||||
class TestForBreakWithLoadSameConsts(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_for_break_with_load_same_consts(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(for_break_with_load_same_consts, x)
|
||||
|
||||
|
||||
def for_break_with_write_pre_defined_name(x: paddle.Tensor):
|
||||
y = None
|
||||
for i in [1, 2, 3]:
|
||||
y = i
|
||||
sot.psdb.breakgraph()
|
||||
return x + 1
|
||||
|
||||
|
||||
class TestForBreakWithWritePreDefinedName(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_for_break_with_write_pre_defined_name(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(for_break_with_write_pre_defined_name, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,103 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# MAKE_FUNCTION
|
||||
# CALL_FUNCTION_KW
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def make_fn_simple(x: paddle.Tensor):
|
||||
def fn(a, b, c, d):
|
||||
return a + b + c + d
|
||||
|
||||
return fn(1, 2, 3, 4) + x
|
||||
|
||||
|
||||
def make_fn_default(x: paddle.Tensor):
|
||||
def fn(a, b, c=5, d=3):
|
||||
return a + b + c + d
|
||||
|
||||
return fn(1, 2) + fn(1, 2, c=3) + x
|
||||
|
||||
|
||||
def make_fn_annotation(x: paddle.Tensor):
|
||||
def fn(a, b: int, c: int, d):
|
||||
return a + b + c + d
|
||||
|
||||
return fn(1, 2, 3, 4) + x
|
||||
|
||||
|
||||
def make_fn_kwdefault(x: paddle.Tensor):
|
||||
def fn(a, b, *, c=3, d=4):
|
||||
return a + b + c + d
|
||||
|
||||
return fn(1, 2) + fn(3, 4, c=1, d=2) + x
|
||||
|
||||
|
||||
def make_fn_closure(x: paddle.Tensor):
|
||||
def fn(a, b, c, d):
|
||||
y = x
|
||||
return a + b + c + d
|
||||
|
||||
return fn(1, 2, 3, 4) + x
|
||||
|
||||
|
||||
def make_fn_mix(x: paddle.Tensor):
|
||||
def fn(a: int = 1, b: float = 2.0, /, *, c: int = 4, d: float = 5):
|
||||
# y = x
|
||||
return a + b + c + d
|
||||
|
||||
return fn(2, 3, c=1, d=2.0) + x
|
||||
|
||||
|
||||
def make_fn_tensor_default(x: paddle.Tensor):
|
||||
tensor = paddle.to_tensor(1.0)
|
||||
|
||||
def fn(a, b, c=tensor):
|
||||
return a + b + c
|
||||
|
||||
return fn(1, 2) + x
|
||||
|
||||
|
||||
def make_fn_tensor_kwdefault(x: paddle.Tensor):
|
||||
tensor = paddle.to_tensor(1.0)
|
||||
|
||||
def fn(*args, c=tensor):
|
||||
return args[0] + args[1] + c
|
||||
|
||||
return fn(1, 2, c=3) + x
|
||||
|
||||
|
||||
class TestMakeFunction(TestCaseBase):
|
||||
def test_simple(self):
|
||||
self.assert_results(make_fn_simple, paddle.to_tensor(1))
|
||||
self.assert_results(make_fn_default, paddle.to_tensor(1))
|
||||
self.assert_results(make_fn_annotation, paddle.to_tensor(1))
|
||||
self.assert_results(make_fn_kwdefault, paddle.to_tensor(1))
|
||||
self.assert_results(make_fn_closure, paddle.to_tensor(1))
|
||||
self.assert_results(make_fn_mix, paddle.to_tensor(1))
|
||||
|
||||
def test_tensor_default(self):
|
||||
self.assert_results(make_fn_tensor_default, paddle.to_tensor(1))
|
||||
self.assert_results(make_fn_tensor_kwdefault, paddle.to_tensor(1))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,387 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import operator
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def unary_positive(x: int):
|
||||
y = +x
|
||||
return y
|
||||
|
||||
|
||||
def unary_negative(x: paddle.Tensor):
|
||||
y = -x
|
||||
return y
|
||||
|
||||
|
||||
def unary_not(x: paddle.Tensor):
|
||||
y = not x
|
||||
return y
|
||||
|
||||
|
||||
def unary_invert(x: paddle.Tensor):
|
||||
y = ~x
|
||||
return y
|
||||
|
||||
|
||||
def binary_power(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x**y
|
||||
return z
|
||||
|
||||
|
||||
def binary_multiply(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x * y
|
||||
return z
|
||||
|
||||
|
||||
def binary_matrix_multiply(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x @ y
|
||||
return z
|
||||
|
||||
|
||||
def binary_floor_divide(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x // y
|
||||
return z
|
||||
|
||||
|
||||
def binary_true_divide(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x / y
|
||||
return z
|
||||
|
||||
|
||||
def binary_modulo(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x % y
|
||||
return z
|
||||
|
||||
|
||||
def binary_add(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x + y
|
||||
return z
|
||||
|
||||
|
||||
def binary_subtract(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x - y
|
||||
return z
|
||||
|
||||
|
||||
def binary_lshift(x: int, y: int):
|
||||
z = x << y
|
||||
return z
|
||||
|
||||
|
||||
def binary_rshift(x: int, y: int):
|
||||
z = x >> y
|
||||
return z
|
||||
|
||||
|
||||
def binary_and(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x & y
|
||||
return z
|
||||
|
||||
|
||||
def binary_or(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x | y
|
||||
return z
|
||||
|
||||
|
||||
def binary_xor(x: paddle.Tensor, y: paddle.Tensor):
|
||||
z = x ^ y
|
||||
return z
|
||||
|
||||
|
||||
def inplace_power(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x **= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_multiply(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x *= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_matrix_multiply(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x @= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_floor_divide(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x //= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_true_divide(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x /= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_modulo(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x %= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_add(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x += y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_subtract(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x -= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_lshift(x: paddle.Tensor, y: int):
|
||||
x <<= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_rshift(x: paddle.Tensor, y: int):
|
||||
x >>= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_and(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x &= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_or(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x |= y
|
||||
return x
|
||||
|
||||
|
||||
def inplace_xor(x: paddle.Tensor, y: paddle.Tensor):
|
||||
x ^= y
|
||||
return x
|
||||
|
||||
|
||||
def list_getitem(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
return operator.getitem(z, 1) + 1
|
||||
|
||||
|
||||
def list_getitem_slice(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
return operator.getitem(z, slice(0, 2))
|
||||
|
||||
|
||||
def list_setitem_int(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
operator.setitem(z, 0, 3)
|
||||
return z
|
||||
|
||||
|
||||
def list_setitem_tensor(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
operator.setitem(z, 1, paddle.to_tensor(3))
|
||||
return z
|
||||
|
||||
|
||||
def list_delitem_int(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
operator.delitem(z, 0)
|
||||
return z
|
||||
|
||||
|
||||
def list_delitem_tensor(x: int, y: paddle.Tensor):
|
||||
z = [x, y]
|
||||
operator.delitem(z, 1)
|
||||
return z
|
||||
|
||||
|
||||
def dict_getitem_int(x: int, y: paddle.Tensor):
|
||||
z = {1: y, 2: y + 1}
|
||||
return operator.getitem(z, 1)
|
||||
|
||||
|
||||
def dict_getitem_tensor(x: int, y: paddle.Tensor):
|
||||
z = {1: y, 2: y + 1}
|
||||
return operator.getitem(z, 2)
|
||||
|
||||
|
||||
def dict_setitem_int(x: int, y: paddle.Tensor):
|
||||
z = {'x': x, 'y': y}
|
||||
operator.setitem(z, 'x', 2)
|
||||
return z
|
||||
|
||||
|
||||
def dict_setitem_tensor(x: int, y: paddle.Tensor):
|
||||
z = {'x': x, 'y': y}
|
||||
operator.setitem(z, 'y', paddle.to_tensor(3))
|
||||
return z
|
||||
|
||||
|
||||
def dict_delitem_int(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
operator.delitem(z, 1)
|
||||
return z
|
||||
|
||||
|
||||
def dict_delitem_tensor(x: int, y: paddle.Tensor):
|
||||
z = {1: x, 2: y + 1}
|
||||
operator.delitem(z, 2)
|
||||
return z
|
||||
|
||||
|
||||
def tuple_getitem_int(x: int, y: paddle.Tensor):
|
||||
x = (x, y)
|
||||
return operator.getitem(x, 0)
|
||||
|
||||
|
||||
def tuple_getitem_tensor(x: int, y: paddle.Tensor):
|
||||
x = (x, y)
|
||||
return operator.getitem(x, 1)
|
||||
|
||||
|
||||
def tuple_getitem_slice(x: int, y: paddle.Tensor):
|
||||
x = (x, y, 1)
|
||||
return operator.getitem(x, slice(0, 2))
|
||||
|
||||
|
||||
def operator_add(x: int, y: paddle.Tensor):
|
||||
return operator.add(x, y)
|
||||
|
||||
|
||||
def operator_mul(x: int, y: paddle.Tensor):
|
||||
return operator.mul(x, y)
|
||||
|
||||
|
||||
def operator_truth(y: paddle.Tensor):
|
||||
return operator.truth(y)
|
||||
|
||||
|
||||
def operator_is_(x: paddle.Tensor, y: paddle.Tensor):
|
||||
return (operator.is_(x, x), operator.is_(x, y))
|
||||
|
||||
|
||||
def operator_in_(x: int, y: list):
|
||||
return x in y
|
||||
|
||||
|
||||
def operator_not_in_(x: int, y: list):
|
||||
return x not in y
|
||||
|
||||
|
||||
def operator_is_not(x: paddle.Tensor, y: paddle.Tensor):
|
||||
return (operator.is_not(x, x), operator.is_not(x, y))
|
||||
|
||||
|
||||
def operator_pos(y: int):
|
||||
return operator.pos(+y)
|
||||
|
||||
|
||||
class TestOperators(TestCaseBase):
|
||||
def test_simple(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(True)
|
||||
c = paddle.to_tensor(3)
|
||||
d = paddle.to_tensor(4)
|
||||
e = paddle.to_tensor([[1, 2], [3, 4], [5, 6]], dtype='float32')
|
||||
f = paddle.to_tensor([[1, 2, 3], [4, 5, 6]], dtype='float32')
|
||||
g = paddle.to_tensor(False)
|
||||
|
||||
self.assert_results(unary_positive, 1)
|
||||
self.assert_results(unary_negative, a)
|
||||
self.assert_results(unary_not, b)
|
||||
self.assert_results(unary_invert, b)
|
||||
|
||||
self.assert_results(binary_power, c, d)
|
||||
self.assert_results(binary_multiply, c, d)
|
||||
self.assert_results(binary_matrix_multiply, e, f)
|
||||
self.assert_results(binary_floor_divide, c, d)
|
||||
self.assert_results(binary_true_divide, c, d)
|
||||
self.assert_results(binary_modulo, c, d)
|
||||
self.assert_results(binary_add, c, d)
|
||||
self.assert_results(binary_subtract, c, d)
|
||||
self.assert_results(binary_lshift, 10, 2)
|
||||
self.assert_results(binary_rshift, 10, 1)
|
||||
self.assert_results(binary_and, b, g)
|
||||
self.assert_results(binary_or, b, g)
|
||||
self.assert_results(binary_xor, b, g)
|
||||
|
||||
self.assert_results(inplace_power, c, d)
|
||||
self.assert_results(inplace_multiply, c, d)
|
||||
self.assert_results(inplace_matrix_multiply, e, f)
|
||||
self.assert_results(inplace_floor_divide, c, d)
|
||||
self.assert_results(inplace_true_divide, c, d)
|
||||
self.assert_results(inplace_modulo, c, d)
|
||||
self.assert_results(inplace_add, c, d)
|
||||
self.assert_results(inplace_subtract, c, d)
|
||||
self.assert_results(inplace_lshift, 10, 2)
|
||||
self.assert_results(inplace_rshift, 10, 1)
|
||||
self.assert_results(inplace_and, b, g)
|
||||
self.assert_results(inplace_or, b, g)
|
||||
self.assert_results(inplace_xor, b, g)
|
||||
|
||||
def test_operator_simple(self):
|
||||
self.assert_results(operator_add, 1, paddle.to_tensor(2))
|
||||
self.assert_results(operator_mul, 1, paddle.to_tensor(2))
|
||||
self.assert_results(operator_truth, paddle.to_tensor(2))
|
||||
self.assert_results(
|
||||
operator_is_, paddle.to_tensor(2), paddle.to_tensor(3)
|
||||
)
|
||||
self.assert_results(
|
||||
operator_is_not, paddle.to_tensor(2), paddle.to_tensor(3)
|
||||
)
|
||||
self.assert_results(operator_pos, 1)
|
||||
self.assert_results(operator_in_, 12, [1, 2, 12])
|
||||
self.assert_results(operator_in_, 12, [1, 2, 3])
|
||||
self.assert_results(operator_not_in_, 12, [1, 2, 3])
|
||||
self.assert_results(operator_not_in_, 12, [1, 2, 3])
|
||||
|
||||
def test_operator_list(self):
|
||||
self.assert_results(list_getitem, 1, paddle.to_tensor(2))
|
||||
self.assert_results(list_getitem_slice, 1, paddle.to_tensor(2))
|
||||
self.assert_results(list_setitem_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results_with_side_effects(
|
||||
list_setitem_tensor, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results(list_delitem_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results(list_delitem_tensor, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_operator_dict(self):
|
||||
self.assert_results(dict_getitem_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results(dict_getitem_tensor, 1, paddle.to_tensor(2))
|
||||
self.assert_results(dict_setitem_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results_with_side_effects(
|
||||
dict_setitem_tensor, 1, paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results(dict_delitem_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results(dict_delitem_tensor, 1, paddle.to_tensor(2))
|
||||
|
||||
def test_operator_tuple(self):
|
||||
self.assert_results(tuple_getitem_int, 1, paddle.to_tensor(2))
|
||||
self.assert_results(tuple_getitem_tensor, 1, paddle.to_tensor(2))
|
||||
self.assert_results(tuple_getitem_slice, 1, paddle.to_tensor(2))
|
||||
|
||||
|
||||
def run_not_eq(x: paddle.Tensor, y: int):
|
||||
out = paddle.reshape(x, [1, -1]) != y
|
||||
out = out.astype('float32')
|
||||
return out
|
||||
|
||||
|
||||
class TestNotEq(TestCaseBase):
|
||||
def test_not_eq(self):
|
||||
x = paddle.to_tensor([2])
|
||||
y = 3
|
||||
self.assert_results(run_not_eq, x, y)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,160 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# BUILD_SLICE (new)
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
def build_list_slice(x: list, y: paddle.Tensor):
|
||||
x[2:4] = [0, 1]
|
||||
return x[0] + y
|
||||
|
||||
|
||||
def build_list_slice_with_step(x: list, y: paddle.Tensor):
|
||||
x[1:5:2] = [0, 1]
|
||||
return x[0] + y
|
||||
|
||||
|
||||
def build_tuple_slice(x: list, y: paddle.Tensor):
|
||||
x[2:4] = (0, 1)
|
||||
return x[0] + y
|
||||
|
||||
|
||||
def build_tuple_slice_with_step(x: list, y: paddle.Tensor):
|
||||
x[1:5:2] = (0, 1)
|
||||
return x[0] + y
|
||||
|
||||
|
||||
def tensor_subscript_ellipsis(x: paddle.Tensor, y: paddle.Tensor):
|
||||
return x[...] + y[...]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_subscript_tensor(x: paddle.Tensor):
|
||||
d0, d1 = paddle.shape(x)
|
||||
return x[: d0 // 2, d1 // 2 : d1]
|
||||
|
||||
|
||||
class TestSlice(TestCaseBase):
|
||||
def test_simple(self):
|
||||
x = list(range(10))
|
||||
y = paddle.arange(10)
|
||||
self.assert_results_with_side_effects(build_list_slice, x, y)
|
||||
self.assert_results_with_side_effects(build_list_slice_with_step, x, y)
|
||||
self.assert_results_with_side_effects(build_tuple_slice, x, y)
|
||||
self.assert_results_with_side_effects(build_tuple_slice_with_step, x, y)
|
||||
|
||||
|
||||
class MyLayer(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.linears = paddle.nn.LayerList(
|
||||
[paddle.nn.Linear(10, 10) for i in range(10)]
|
||||
)
|
||||
|
||||
def forward(self, x):
|
||||
for i, l in enumerate(self.linears):
|
||||
x = self.linears[i // 2](x) + l(x)
|
||||
return x
|
||||
|
||||
|
||||
def layer_list_slice(layer, x):
|
||||
out = layer(x)
|
||||
return out
|
||||
|
||||
|
||||
class TestLayerList(TestCaseBase):
|
||||
def test_layer_list_slice(self):
|
||||
layer = MyLayer()
|
||||
x = paddle.randn([5, 10])
|
||||
self.assert_results(layer_list_slice, layer, x)
|
||||
|
||||
|
||||
def tensor_slice(x: paddle.Tensor):
|
||||
return x[1, 1, 1] + 1
|
||||
|
||||
|
||||
class TestTensorSlice(TestCaseBase):
|
||||
def test_tensor_slice(self):
|
||||
x = paddle.randn([4, 3, 10])
|
||||
self.assert_results(tensor_slice, x)
|
||||
|
||||
|
||||
class TestTensorEllipsis(TestCaseBase):
|
||||
def test_tensor_subscript_ellipsis(self):
|
||||
x = paddle.rand((10,))
|
||||
y = paddle.rand((10, 10))
|
||||
self.assert_results(tensor_subscript_ellipsis, x, y)
|
||||
|
||||
|
||||
class TestTensorSubscriptTensor(TestCaseBase):
|
||||
def test_tensor_subscript_tensor(self):
|
||||
x = paddle.rand((10, 10))
|
||||
self.assert_results(tensor_subscript_tensor, x)
|
||||
|
||||
|
||||
class LayerListNet(paddle.nn.Layer):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.layer_list = paddle.nn.LayerList(
|
||||
[paddle.nn.Linear(5, 5), paddle.nn.Linear(5, 5)]
|
||||
)
|
||||
|
||||
def forward(self, x):
|
||||
out = self.layer_list[0](x)
|
||||
for layer in self.layer_list[1:]:
|
||||
out = layer(out)
|
||||
return out
|
||||
|
||||
|
||||
class TestLayerListSlice(TestCaseBase):
|
||||
def test_layer_list_slice(self):
|
||||
x = paddle.randn([2, 5])
|
||||
net = LayerListNet()
|
||||
self.assert_results(layer_list_slice, net, x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def string_slice(x: str):
|
||||
return x[2:7:2] + x[1:5] + x[4]
|
||||
|
||||
|
||||
class TestStringSlice(TestCaseBase):
|
||||
def test_string_slice(self):
|
||||
x = "1234567"
|
||||
self.assert_results(string_slice, x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_slice_as_input(x: slice):
|
||||
tensor = paddle.to_tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
return tensor[x]
|
||||
|
||||
|
||||
class TestSliceAsInput(TestCaseBase):
|
||||
def test_slice_as_input(self):
|
||||
x = slice(2, 7, 2)
|
||||
self.assert_results(tensor_slice_as_input, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,73 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.nn.functional import relu
|
||||
|
||||
|
||||
def paddle_api_method_call(x: paddle.Tensor):
|
||||
m = x + 2
|
||||
m = paddle.nn.functional.relu(m)
|
||||
return m
|
||||
|
||||
|
||||
def paddle_api_function_call(x: paddle.Tensor):
|
||||
m = x + 2
|
||||
m = relu(m)
|
||||
return m
|
||||
|
||||
|
||||
def paddle_api_function_call_concat(
|
||||
x: paddle.Tensor, y: paddle.Tensor, axis: int
|
||||
):
|
||||
return paddle.concat([x, y], axis=axis)
|
||||
|
||||
|
||||
def paddle_api_function_breakgraph_when_type_error(
|
||||
x: paddle.Tensor, axis: paddle.Tensor
|
||||
):
|
||||
return paddle.nn.functional.softmax(x, axis=axis)
|
||||
|
||||
|
||||
class TestPaddleApiCall(TestCaseBase):
|
||||
def test_paddle_api_method_call(self):
|
||||
self.assert_results(paddle_api_method_call, paddle.to_tensor(2.0))
|
||||
self.assert_results(paddle_api_method_call, paddle.to_tensor(-5.0))
|
||||
self.assert_results(paddle_api_method_call, paddle.to_tensor(0.0))
|
||||
|
||||
def test_paddle_api_function_call(self):
|
||||
self.assert_results(paddle_api_function_call, paddle.to_tensor(2.0))
|
||||
self.assert_results(paddle_api_function_call, paddle.to_tensor(-5.0))
|
||||
self.assert_results(paddle_api_function_call, paddle.to_tensor(0.0))
|
||||
|
||||
def test_paddle_api_function_call_concat(self):
|
||||
a = paddle.to_tensor([[1, 2], [3, 4]])
|
||||
b = paddle.to_tensor([[5, 6], [7, 8]])
|
||||
self.assert_results(paddle_api_function_call_concat, a, b, 0)
|
||||
self.assert_results(paddle_api_function_call_concat, a, b, 1)
|
||||
|
||||
def test_paddle_api_function_breakgraph_when_type_error(self):
|
||||
x = paddle.to_tensor([[1, 2], [3, 4]], dtype=paddle.float32)
|
||||
axis = paddle.to_tensor(1)
|
||||
self.assert_results(
|
||||
paddle_api_function_breakgraph_when_type_error, x, axis
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,94 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
class SimpleNet(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.linear1 = paddle.nn.Linear(10, 1)
|
||||
|
||||
def forward(self, x):
|
||||
out1 = self.linear1(x)
|
||||
return out1
|
||||
|
||||
|
||||
class SimpleNet_bound(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.linear1 = paddle.nn.Linear(10, 1)
|
||||
|
||||
def add(self, x):
|
||||
return x + 1
|
||||
|
||||
def forward(self, x):
|
||||
x = self.add(x)
|
||||
out1 = self.linear1(x)
|
||||
return out1
|
||||
|
||||
|
||||
def net_call(x: paddle.Tensor, net):
|
||||
return net(x)
|
||||
|
||||
|
||||
def net_call_passed_by_user(x: paddle.Tensor, net_forward):
|
||||
return net_forward(x)
|
||||
|
||||
|
||||
class SimpleNetWithSequenital(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.seq = paddle.nn.Sequential(
|
||||
paddle.nn.Linear(10, 10),
|
||||
paddle.nn.Linear(10, 10),
|
||||
paddle.nn.Linear(10, 1),
|
||||
)
|
||||
|
||||
def forward(self, x):
|
||||
out1 = self.seq(x)
|
||||
return out1
|
||||
|
||||
|
||||
class TestLayer(TestCaseBase):
|
||||
def test_layer(self):
|
||||
x = paddle.rand((10,))
|
||||
y = paddle.rand((10, 10))
|
||||
net = SimpleNet()
|
||||
self.assert_results(net_call, x, net)
|
||||
self.assert_results(net_call, y, net)
|
||||
self.assert_results(net_call_passed_by_user, x, net.forward)
|
||||
|
||||
def test_layer_with_sequential(self):
|
||||
x = paddle.rand((10,))
|
||||
y = paddle.rand((10, 10))
|
||||
net = SimpleNetWithSequenital()
|
||||
self.assert_results(net_call, x, net)
|
||||
self.assert_results(net_call, y, net)
|
||||
self.assert_results(net_call_passed_by_user, x, net.forward)
|
||||
|
||||
def test_bound(self):
|
||||
x = paddle.rand((10,))
|
||||
y = paddle.rand((10, 10))
|
||||
net = SimpleNet_bound()
|
||||
self.assert_results(net_call, x, net)
|
||||
self.assert_results(net_call, y, net)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,154 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_method_call_1(x: paddle.Tensor):
|
||||
y = x + 1
|
||||
return y.mean()
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_method_call_2(a: paddle.Tensor, b: paddle.Tensor):
|
||||
c = a.add(b)
|
||||
d = c.multiply(a)
|
||||
e = d.subtract(b)
|
||||
f = e.divide(a)
|
||||
g = f.pow(2) + f.abs().sqrt()
|
||||
h = (g.abs() + 1).log() - (g / g.max()).exp()
|
||||
i = h.sin() + h.cos()
|
||||
return i
|
||||
|
||||
|
||||
def tensor_method_passed_by_user(a: paddle.Tensor, func: paddle.Tensor):
|
||||
return func(a)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_method_property_without_breakgraph(
|
||||
a: paddle.Tensor, b: paddle.Tensor
|
||||
):
|
||||
return (
|
||||
a.name,
|
||||
a.persistable,
|
||||
a.dtype,
|
||||
a.is_tensor(),
|
||||
a @ b.T.astype(a.dtype)
|
||||
+ len(a.shape)
|
||||
+ b.size
|
||||
+ a.ndim
|
||||
+ a.dim()
|
||||
+ a.rank(),
|
||||
a.element_size(),
|
||||
)
|
||||
|
||||
|
||||
def tensor_method_property_with_breakgraph(a: paddle.Tensor, b: paddle.Tensor):
|
||||
return (
|
||||
a.type,
|
||||
a.numpy(),
|
||||
a.tolist(),
|
||||
str(a.place),
|
||||
a.clear_gradient(),
|
||||
a.is_dense(),
|
||||
)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_method_property_mT(a: paddle.Tensor):
|
||||
return a.mT
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def middle_tensor_name(a: paddle.Tensor, b: paddle.Tensor):
|
||||
c = a + b
|
||||
return c.name
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_numel(x: paddle.Tensor):
|
||||
return x.numel(), int(x.size)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_dim(x: paddle.Tensor):
|
||||
return x.dim(), x.ndimension(), x.ndim, x.rank()
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tensor_len(x: paddle.Tensor):
|
||||
return len(x)
|
||||
|
||||
|
||||
class TestTensorMethod(TestCaseBase):
|
||||
def test_tensor_method_1(self):
|
||||
x = paddle.rand([10])
|
||||
y = paddle.rand([2, 4, 6])
|
||||
self.assert_results(tensor_method_call_1, x)
|
||||
self.assert_results(tensor_method_call_1, y)
|
||||
|
||||
def test_tensor_method_2(self):
|
||||
x = paddle.rand([42])
|
||||
y = paddle.rand([42])
|
||||
self.assert_results(tensor_method_call_2, x, y)
|
||||
|
||||
def test_tensor_method_passed_by_user(self):
|
||||
x = paddle.rand([42])
|
||||
y = paddle.rand([42])
|
||||
self.assert_results(tensor_method_passed_by_user, x, y.add)
|
||||
|
||||
def test_tensor_method_property(self):
|
||||
x = paddle.rand([42, 24], dtype='float64')
|
||||
y = paddle.rand([42, 24], dtype='float32')
|
||||
self.assert_results(tensor_method_property_without_breakgraph, x, y)
|
||||
self.assert_results(tensor_method_property_with_breakgraph, x, y)
|
||||
|
||||
@unittest.skip("TODO: dynamic tensor name is different")
|
||||
def test_middle_tensor_name(self):
|
||||
x = paddle.rand([42, 24])
|
||||
y = paddle.rand([42, 24])
|
||||
self.assert_results(middle_tensor_name, x, y)
|
||||
|
||||
def test_tensor_method_property_mT(self):
|
||||
x = paddle.rand([42, 24, 2, 2, 3, 2], dtype='float64')
|
||||
y = paddle.rand([42, 24, 2, 3, 3, 2], dtype='float32')
|
||||
self.assert_results(tensor_method_property_mT, x)
|
||||
self.assert_results(tensor_method_property_mT, y)
|
||||
|
||||
def test_tensor_numel(self):
|
||||
x = paddle.rand([2, 3], dtype='float32')
|
||||
self.assert_results(tensor_numel, x)
|
||||
x = paddle.rand([3, 3], dtype='float32')
|
||||
self.assert_results(tensor_numel, x) # test dynamic shape
|
||||
|
||||
def test_tensor_dim(self):
|
||||
x = paddle.rand([2, 3], dtype='float32')
|
||||
self.assert_results(tensor_dim, x)
|
||||
|
||||
def test_tensor_len(self):
|
||||
x = paddle.rand([2, 3], dtype='float32')
|
||||
self.assert_results(tensor_len, x)
|
||||
x = paddle.rand([3, 3], dtype='float32')
|
||||
self.assert_results(tensor_len, x) # test dynamic shape
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,261 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import inspect
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
def foo(x: int, y: paddle.Tensor):
|
||||
z = 3
|
||||
|
||||
def local(a, b=5):
|
||||
return a + x + z + b + y
|
||||
|
||||
return local(4) + z
|
||||
|
||||
|
||||
def foo2(y: paddle.Tensor, x=1):
|
||||
"""
|
||||
Test strip default value
|
||||
"""
|
||||
z = 3
|
||||
|
||||
def local(a, b=5):
|
||||
return a + x + z + b + y
|
||||
|
||||
return local(4)
|
||||
|
||||
|
||||
def foo3(y: paddle.Tensor, x=1):
|
||||
"""
|
||||
Test Closure Band Default
|
||||
"""
|
||||
z = 3
|
||||
|
||||
def local(a, b=5):
|
||||
nonlocal z
|
||||
z = 4
|
||||
return a + x + z + b + y
|
||||
|
||||
return local(4)
|
||||
|
||||
|
||||
global_z = 3
|
||||
|
||||
|
||||
def test_global(y: paddle.Tensor):
|
||||
"""
|
||||
Test Global variable
|
||||
"""
|
||||
|
||||
def local(a, b=5):
|
||||
global global_z
|
||||
global_z += 1
|
||||
return a + global_z + b + y
|
||||
|
||||
return local(1)
|
||||
|
||||
|
||||
def multi(c):
|
||||
return c + 2
|
||||
|
||||
|
||||
def wrapper_function(func):
|
||||
a = 2
|
||||
|
||||
def inner():
|
||||
return func(a)
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
wrapped_multi = wrapper_function(multi)
|
||||
|
||||
|
||||
def foo5(y: paddle.Tensor):
|
||||
"""
|
||||
Test incoming closures
|
||||
"""
|
||||
a = wrapped_multi()
|
||||
return a
|
||||
|
||||
|
||||
def outwrapper(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def foo6(y: paddle.Tensor):
|
||||
"""
|
||||
Test Decorator
|
||||
"""
|
||||
|
||||
@outwrapper
|
||||
def load_1(a, b=5):
|
||||
return a + b
|
||||
|
||||
return load_1(1)
|
||||
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def numpy_sum(m):
|
||||
"""
|
||||
Test loop call
|
||||
|
||||
Example: a->b->c->a
|
||||
"""
|
||||
a = np.array([1, 2, 3])
|
||||
tmp = np.sum(a)
|
||||
return m + 1
|
||||
|
||||
|
||||
def lambda_closure(x, m):
|
||||
"""
|
||||
lambda closure.
|
||||
"""
|
||||
|
||||
def break_graph_closure():
|
||||
print("yes")
|
||||
return x + m
|
||||
|
||||
return break_graph_closure()
|
||||
|
||||
|
||||
# motivated by python builtin decorator
|
||||
def kwargs_wrapper(func):
|
||||
sig = inspect.signature(func)
|
||||
|
||||
def inner(*args, **kwargs):
|
||||
return func(*args, **kwargs)
|
||||
|
||||
inner.__signature__ = sig
|
||||
return inner
|
||||
|
||||
|
||||
@kwargs_wrapper
|
||||
def func7(a, b):
|
||||
return a + b
|
||||
|
||||
|
||||
def foo7():
|
||||
return func7(3, 5)
|
||||
|
||||
|
||||
def create_closure():
|
||||
x = 1
|
||||
|
||||
def closure():
|
||||
return x + 1
|
||||
|
||||
return closure
|
||||
|
||||
|
||||
class TestClosure(TestCaseBase):
|
||||
def test_closure(self):
|
||||
self.assert_results(foo, 1, paddle.to_tensor(2))
|
||||
self.assert_results(foo2, paddle.to_tensor(2))
|
||||
self.assert_results(foo3, paddle.to_tensor(2))
|
||||
self.assert_results_with_global_check(
|
||||
test_global, ["global_z"], paddle.to_tensor(2)
|
||||
)
|
||||
self.assert_results(foo5, paddle.to_tensor(2))
|
||||
self.assert_results(foo6, paddle.to_tensor(2))
|
||||
self.assert_results(numpy_sum, paddle.to_tensor(1))
|
||||
with strict_mode_guard(False):
|
||||
self.assert_results(
|
||||
lambda_closure, paddle.to_tensor(2), paddle.to_tensor(1)
|
||||
)
|
||||
|
||||
|
||||
class TestClosure2(TestCaseBase):
|
||||
def test_closure(self):
|
||||
self.assert_results(foo7)
|
||||
|
||||
|
||||
# Side Effect.
|
||||
def test_slice_in_for_loop(x, iter_num=3):
|
||||
x = paddle.to_tensor(x)
|
||||
a = []
|
||||
# Use `paddle.full` so that static analysis can analyze the type of iter_num is Tensor
|
||||
iter_num = paddle.full(
|
||||
shape=[1], fill_value=iter_num, dtype="int32"
|
||||
) # TODO(liym27): Delete it if the type of parameter iter_num can be resolved
|
||||
|
||||
for i in range(iter_num):
|
||||
a.append(x)
|
||||
|
||||
for i in range(iter_num):
|
||||
a[i] = x
|
||||
out = a[2]
|
||||
return out
|
||||
|
||||
|
||||
class TestClosure3(TestCaseBase):
|
||||
def test_closure(self):
|
||||
tx = paddle.to_tensor([1.0, 2.0, 3.0])
|
||||
# need side effect of list.
|
||||
# self.assert_results(test_slice_in_for_loop, tx)
|
||||
|
||||
|
||||
def non_local_test(t: paddle.Tensor):
|
||||
a = 1
|
||||
|
||||
def func1():
|
||||
nonlocal a
|
||||
t = a
|
||||
a = 2
|
||||
return t
|
||||
|
||||
def func2():
|
||||
nonlocal a
|
||||
a = 1
|
||||
return a
|
||||
|
||||
t += func1() # add 2
|
||||
t += func2() # add 1
|
||||
t += a # add 1
|
||||
return t
|
||||
|
||||
|
||||
class TestClosure4(TestCaseBase):
|
||||
def test_closure(self):
|
||||
tx = paddle.to_tensor([1.0])
|
||||
self.assert_results(non_local_test, tx)
|
||||
|
||||
|
||||
class TestCreateClosure(TestCaseBase):
|
||||
def test_create_closure(self):
|
||||
closure = create_closure()
|
||||
self.assert_results(closure)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
# Instructions:
|
||||
# LOAD_CLOSURE
|
||||
# LOAD_DEREF
|
||||
# LOAD_CLASSDEREF
|
||||
# STORE_DEREF
|
||||
# DELETE_DEREF
|
||||
# STORE_GLOBAL
|
||||
@@ -0,0 +1,83 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import assert_true, check_no_breakgraph
|
||||
|
||||
|
||||
def string_format(x: paddle.Tensor):
|
||||
whilespace = 123
|
||||
hello_world = f"Hello {whilespace} World"
|
||||
z = assert_true(hello_world == "Hello 123 World")
|
||||
hello_world2 = f"Hello {whilespace}{whilespace} World"
|
||||
z = assert_true(hello_world2 == "Hello 123123 World")
|
||||
hello_world_lower = "Hello World".lower()
|
||||
z = assert_true(hello_world_lower == "hello world")
|
||||
return x + 1
|
||||
|
||||
|
||||
def string_lower(x: paddle.Tensor):
|
||||
hello_world_lower = "Hello World".lower()
|
||||
z = assert_true(hello_world_lower == "hello world")
|
||||
return x + 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def str_startswith():
|
||||
s = "Hello World"
|
||||
a1 = s.startswith("Hello")
|
||||
a2 = s.startswith("World")
|
||||
a3 = s.startswith("Hello World")
|
||||
a4 = s.startswith("Hello World!")
|
||||
a5 = s.startswith("Hello", 5)
|
||||
a6 = s.startswith("Hello", 1, 4)
|
||||
a7 = s.startswith("Hello", 0, 11)
|
||||
return (a1, a2, a3, a4, a5, a6, a7)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def str_endswith():
|
||||
s = "Hello World"
|
||||
a1 = s.endswith("Hello")
|
||||
a2 = s.endswith("World")
|
||||
a3 = s.endswith("Hello World")
|
||||
a4 = s.endswith("Hello World!")
|
||||
a5 = s.endswith("Hello", 5)
|
||||
a6 = s.endswith("Hello", 0, 4)
|
||||
a7 = s.endswith("Hello", 1, 11)
|
||||
return (a1, a2, a3, a4, a5, a6, a7)
|
||||
|
||||
|
||||
class TestString(TestCaseBase):
|
||||
def test_string_format(self):
|
||||
self.assert_results(string_format, paddle.to_tensor(1))
|
||||
|
||||
def test_string_lower(self):
|
||||
self.assert_results(string_lower, paddle.to_tensor(1))
|
||||
|
||||
def test_str_startswith(self):
|
||||
self.assert_results(str_startswith)
|
||||
|
||||
def test_str_endswith(self):
|
||||
self.assert_results(str_endswith)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,175 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit import sot
|
||||
|
||||
global_x = 1
|
||||
global_y = paddle.to_tensor(2)
|
||||
global_z = None
|
||||
global_del_val = 1
|
||||
global_dict = {}
|
||||
global_list = [1, 2]
|
||||
global_inline = 0
|
||||
|
||||
|
||||
def global_func_int():
|
||||
global global_x
|
||||
global_x = global_x + 1
|
||||
return global_x
|
||||
|
||||
|
||||
def global_func_int_add():
|
||||
global global_x
|
||||
global_x = global_x + global_x
|
||||
return global_x + global_x
|
||||
|
||||
|
||||
def global_func_tensor_int_add(tensor_y: paddle.Tensor):
|
||||
global global_x
|
||||
global_x += 1
|
||||
return global_x + tensor_y
|
||||
|
||||
|
||||
def global_multiple_update():
|
||||
global global_x
|
||||
global_x = 999
|
||||
global_x = 888
|
||||
global_x = 777
|
||||
return global_x - 1
|
||||
|
||||
|
||||
def global_func_tensor():
|
||||
global global_y
|
||||
global_y = global_y + global_y
|
||||
return global_y
|
||||
|
||||
|
||||
def global_func_tensor_add():
|
||||
global global_y
|
||||
global_y = global_y + global_y
|
||||
return global_y + global_y
|
||||
|
||||
|
||||
def global_func():
|
||||
global global_x
|
||||
global global_y
|
||||
global global_z
|
||||
|
||||
global_z = global_x + global_y
|
||||
return global_z
|
||||
|
||||
|
||||
def global_del_global():
|
||||
global global_del_val
|
||||
|
||||
del global_del_val
|
||||
|
||||
|
||||
def global_func_dict():
|
||||
global global_dict
|
||||
global_dict["key"] = "value"
|
||||
global_dict.update({"test_key1": "test_value2"})
|
||||
return global_dict
|
||||
|
||||
|
||||
def global_func_control1():
|
||||
global global_dict
|
||||
if "key" in global_dict:
|
||||
del global_dict["key"]
|
||||
return global_dict
|
||||
|
||||
|
||||
def global_func_control2():
|
||||
global global_list
|
||||
for i in range(len(global_list)):
|
||||
global_list[i] = global_list[i] + 1
|
||||
return global_list
|
||||
|
||||
|
||||
def global_func_inline_inner_1():
|
||||
global global_inline
|
||||
global_func_inline_inner_2()
|
||||
global_inline += 1
|
||||
|
||||
|
||||
def global_func_inline_inner_2():
|
||||
global global_inline
|
||||
global_inline += 1
|
||||
|
||||
|
||||
def global_func_inline():
|
||||
global_func_inline_inner_1()
|
||||
global global_inline
|
||||
return global_inline
|
||||
|
||||
|
||||
class TestGlobal(TestCaseBase):
|
||||
def test_global_func_int(self):
|
||||
global global_x
|
||||
self.assert_results_with_global_check(global_func_int, ["global_x"])
|
||||
global_x += 1
|
||||
self.assert_results_with_global_check(global_func_int, ["global_x"])
|
||||
self.assert_results_with_global_check(global_func_int_add, ["global_x"])
|
||||
|
||||
def test_global_multiple_update(self):
|
||||
self.assert_results_with_global_check(
|
||||
global_multiple_update, ["global_x"]
|
||||
)
|
||||
|
||||
def test_global_func_tensor_int_add(self):
|
||||
self.assert_results_with_global_check(
|
||||
global_func_tensor_int_add, ["global_x"], paddle.to_tensor(1)
|
||||
)
|
||||
|
||||
def test_global_func_tensor(self):
|
||||
self.assert_results_with_global_check(global_func_tensor, ["global_y"])
|
||||
self.assert_results_with_global_check(
|
||||
global_func_tensor_add, ["global_y"]
|
||||
)
|
||||
|
||||
def test_global_func(self):
|
||||
self.assert_results_with_global_check(global_func, ["global_z"])
|
||||
self.assertIn("global_del_val", global_del_global.__globals__)
|
||||
sot.symbolic_translate(global_del_global)()
|
||||
self.assertNotIn("global_del_val", global_del_global.__globals__)
|
||||
|
||||
def test_global_func_dict(self):
|
||||
self.assert_results_with_global_check(global_func_dict, ["global_dict"])
|
||||
self.assert_results_with_global_check(
|
||||
global_func_control1, ["global_dict"]
|
||||
)
|
||||
|
||||
def test_global_func_list(self):
|
||||
self.assert_results_with_global_check(
|
||||
global_func_control2, ["global_list"]
|
||||
)
|
||||
|
||||
def test_global_func_inline(self):
|
||||
global global_inline
|
||||
global_inline = 0
|
||||
sot.symbolic_translate(global_func_inline)()
|
||||
self.assertEqual(global_inline, 2)
|
||||
sot.symbolic_translate(global_func_inline)()
|
||||
self.assertEqual(global_inline, 4)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,190 @@
|
||||
# Copyright (c) 2025 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 operator
|
||||
import unittest
|
||||
from functools import reduce
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils.envs import strict_mode_guard
|
||||
|
||||
|
||||
def create_simple_generator(a, b):
|
||||
yield a
|
||||
yield b
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def simple_generator_user():
|
||||
gen = create_simple_generator(1, 2)
|
||||
x = next(gen)
|
||||
y = next(gen)
|
||||
return x, y
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def genexpr_user():
|
||||
gen = (i for i in range(2))
|
||||
x = next(gen)
|
||||
y = next(gen)
|
||||
return x, y
|
||||
|
||||
|
||||
def echo():
|
||||
recv = None
|
||||
recv = yield recv
|
||||
recv = yield recv
|
||||
recv = yield recv
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def generator_send():
|
||||
s = echo()
|
||||
init = next(s)
|
||||
recv_1 = s.send(2)
|
||||
recv_2 = s.send(3)
|
||||
return init, recv_1, recv_2
|
||||
|
||||
|
||||
def yield_from_generator():
|
||||
yield from create_simple_generator(1, 2)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def generator_yield_from_generator_user():
|
||||
s = yield_from_generator()
|
||||
x = next(s)
|
||||
y = next(s)
|
||||
return x, y
|
||||
|
||||
|
||||
def yield_from_iterable():
|
||||
yield from [1, 2]
|
||||
|
||||
|
||||
def generator_yield_from_iterable_user():
|
||||
s = yield_from_iterable()
|
||||
x = next(s)
|
||||
y = next(s)
|
||||
return x, y
|
||||
|
||||
|
||||
def for_iterate_generator():
|
||||
out = 0
|
||||
for i in create_simple_generator(1, 2):
|
||||
out += i
|
||||
return out
|
||||
|
||||
|
||||
def create_simple_generator_with_breakgraph():
|
||||
yield 1
|
||||
sot.psdb.breakgraph()
|
||||
yield 2
|
||||
|
||||
|
||||
def simple_generator_user_with_breakgraph():
|
||||
gen = create_simple_generator_with_breakgraph()
|
||||
x = next(gen)
|
||||
y = next(gen)
|
||||
return x + y
|
||||
|
||||
|
||||
def create_simple_generator_with_outer_breakgraph():
|
||||
yield 1
|
||||
yield 2
|
||||
|
||||
|
||||
def simple_generator_user_with_outer_breakgraph():
|
||||
gen = create_simple_generator_with_outer_breakgraph()
|
||||
x = next(gen)
|
||||
sot.psdb.breakgraph()
|
||||
y = next(gen)
|
||||
return x + y
|
||||
|
||||
|
||||
class TestGeneratorCommon(TestCaseBase):
|
||||
def test_generator_simple(self):
|
||||
self.assert_results(simple_generator_user)
|
||||
|
||||
def test_generator_send(self):
|
||||
self.assert_results(generator_send)
|
||||
|
||||
def test_genexpr(self):
|
||||
self.assert_results(genexpr_user)
|
||||
|
||||
def test_generator_yield_from_generator(self):
|
||||
self.assert_results(generator_yield_from_generator_user)
|
||||
|
||||
def test_generator_yield_from_iterable(self):
|
||||
self.assert_results(generator_yield_from_iterable_user)
|
||||
|
||||
def test_for_iterate_generator(self):
|
||||
self.assert_results(for_iterate_generator)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_generator_simple_with_breakgraph(self):
|
||||
self.assert_results(simple_generator_user_with_breakgraph)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_generator_simple_with_outer_breakgraph(self):
|
||||
self.assert_results(simple_generator_user_with_outer_breakgraph)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def generator_sum():
|
||||
return sum(i for i in range(10))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def generator_max():
|
||||
return max((-2) ** i for i in range(10))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def generator_min():
|
||||
return min((-2) ** i for i in range(10))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def generator_reduce():
|
||||
return reduce(operator.add, (i for i in range(10)))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def generator_map():
|
||||
return list(map(lambda x: x**2, (i for i in range(10)))) # noqa: C417
|
||||
|
||||
|
||||
class TestGeneratorDispatch(TestCaseBase):
|
||||
def test_generator_sum(self):
|
||||
self.assert_results(generator_sum)
|
||||
|
||||
def test_generator_max(self):
|
||||
self.assert_results(generator_max)
|
||||
|
||||
def test_generator_min(self):
|
||||
self.assert_results(generator_min)
|
||||
|
||||
def test_generator_reduce(self):
|
||||
self.assert_results(generator_reduce)
|
||||
|
||||
def test_generator_map(self):
|
||||
self.assert_results(generator_map)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,426 @@
|
||||
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils.exceptions import InnerError
|
||||
|
||||
sot_test_dir = os.path.dirname(__file__)
|
||||
sys.path.insert(0, os.path.abspath(f'{sot_test_dir}/../dygraph_to_static'))
|
||||
|
||||
from dygraph_to_static_utils import Dy2StTestBase, test_default_mode_only
|
||||
|
||||
|
||||
# ---------------------- test single inheritance case ----------------------
|
||||
class A:
|
||||
@check_no_breakgraph
|
||||
def add2(self, x):
|
||||
return x + 2
|
||||
|
||||
@check_no_breakgraph
|
||||
def add3(self, x):
|
||||
return x + 3
|
||||
|
||||
|
||||
class B(A):
|
||||
@check_no_breakgraph
|
||||
def test_super_no_args_add2(self, x):
|
||||
y = super().add2(x)
|
||||
return y
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_super_with_args_add3(self, x):
|
||||
y = super(B, self).add3(x) # noqa: UP008
|
||||
return y
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_super_both_add5(self, x):
|
||||
return super().add2(x) + super(B, self).add3(x) # noqa: UP008
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_self_name_me(me, x):
|
||||
# Test case where the instance is referred to as 'me' instead of 'self'
|
||||
return super(B, me).add2(x) # noqa: UP008
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_self_name_this(this, x):
|
||||
# Test case where the instance is referred to as 'this' instead of 'self'
|
||||
return super(B, this).add2(x) # noqa: UP008
|
||||
|
||||
|
||||
class TestSingleInheritance(TestCaseBase):
|
||||
def test_super_no_args(self):
|
||||
self.assert_results(B().test_super_no_args_add2, paddle.to_tensor(33))
|
||||
|
||||
def test_super_with_args(self):
|
||||
self.assert_results(B().test_super_with_args_add3, paddle.to_tensor(33))
|
||||
|
||||
def test_super_both(self):
|
||||
self.assert_results(B().test_super_both_add5, paddle.to_tensor(33))
|
||||
|
||||
def test_super_self_name(self):
|
||||
self.assert_results(B().test_self_name_me, paddle.to_tensor(33))
|
||||
self.assert_results(B().test_self_name_this, paddle.to_tensor(33))
|
||||
|
||||
def test_guard_run(self): # test guard
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(
|
||||
B().test_super_no_args_add2, paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
B().test_super_no_args_add2, paddle.to_tensor(2)
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(
|
||||
B().test_super_no_args_add2, paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
B().test_super_no_args_add2, paddle.to_tensor(2)
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(
|
||||
B().test_super_with_args_add3, paddle.to_tensor(3)
|
||||
)
|
||||
self.assert_results(
|
||||
B().test_super_with_args_add3, paddle.to_tensor(4)
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(B().test_super_both_add5, paddle.to_tensor(5))
|
||||
self.assert_results(B().test_super_both_add5, paddle.to_tensor(6))
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
|
||||
# ---------------------- test multiple inheritance case ----------------------
|
||||
class X:
|
||||
@check_no_breakgraph
|
||||
def addx(self, x):
|
||||
return 1 + x
|
||||
|
||||
|
||||
class Y:
|
||||
@check_no_breakgraph
|
||||
def addx(self, x):
|
||||
return 2 + x
|
||||
|
||||
|
||||
class Z(X, Y):
|
||||
@check_no_breakgraph
|
||||
def addx(self, x):
|
||||
return super().addx(x) + 3 + x
|
||||
|
||||
|
||||
class P(Y):
|
||||
@check_no_breakgraph
|
||||
def addx(self, x):
|
||||
return super(P, self).addx(x) + 4 + x # noqa: UP008
|
||||
|
||||
|
||||
class Q(Z, P):
|
||||
@check_no_breakgraph
|
||||
def addx(self, x):
|
||||
return super(Q, self).addx(x) + 5 + x # noqa: UP008
|
||||
|
||||
@check_no_breakgraph
|
||||
def addxP(self, x):
|
||||
return super(P, self).addx(x) + 5 + x
|
||||
|
||||
@check_no_breakgraph
|
||||
def addxZ(self, x):
|
||||
return super(Z, self).addx(x) + 5 + x
|
||||
|
||||
|
||||
# Inheritance diagram
|
||||
# X Y
|
||||
# \ / \
|
||||
# \ / \
|
||||
# Z P
|
||||
# \ /
|
||||
# \ /
|
||||
# Q
|
||||
class TestMultipleInheritance(TestCaseBase):
|
||||
def test_with_args(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
self.assert_results(Q().addx, x)
|
||||
self.assert_results(Q().addxP, x)
|
||||
self.assert_results(Q().addxZ, x)
|
||||
|
||||
def test_guard_run(self): # test guard
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(Q().addx, paddle.to_tensor(1))
|
||||
self.assert_results(Q().addx, paddle.to_tensor(2))
|
||||
self.assert_results(Q().addx, paddle.to_tensor(3))
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(Q().addxP, paddle.to_tensor(4))
|
||||
self.assert_results(Q().addxP, paddle.to_tensor(5))
|
||||
self.assert_results(Q().addxP, paddle.to_tensor(6))
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(Q().addxZ, paddle.to_tensor(7))
|
||||
self.assert_results(Q().addxZ, paddle.to_tensor(8))
|
||||
self.assert_results(Q().addxZ, paddle.to_tensor(9))
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(Q().addxP, paddle.to_tensor(4))
|
||||
self.assert_results(Q().addxP, paddle.to_tensor(5))
|
||||
self.assert_results(Q().addxP, paddle.to_tensor(6))
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
# ---------------------- test `super()` as input ----------------------
|
||||
class ClassSuperAsInput:
|
||||
@check_no_breakgraph
|
||||
def fn(self, x):
|
||||
return x + 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def super_as_input(spr):
|
||||
return spr.fn(2)
|
||||
|
||||
|
||||
class TestSuperAsInput1(TestCaseBase, ClassSuperAsInput):
|
||||
def test_super_as_input(self):
|
||||
self.assert_results(super_as_input, super())
|
||||
|
||||
def test_guard_run(self): # test guard
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(super_as_input, super())
|
||||
self.assert_results(super_as_input, super())
|
||||
self.assert_results(super_as_input, super())
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
|
||||
class ClassSuperAsInputA:
|
||||
@check_no_breakgraph
|
||||
def test_fn(self, x):
|
||||
return x + 1
|
||||
|
||||
|
||||
class ClassSuperAsInputB(ClassSuperAsInputA):
|
||||
@check_no_breakgraph
|
||||
def test_fn(self, x):
|
||||
return x + 4
|
||||
|
||||
|
||||
class ClassSuperAsInputC(ClassSuperAsInputB):
|
||||
@check_no_breakgraph
|
||||
def super_as_input(self, spr, x):
|
||||
return spr.test_fn(x)
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_super_as_input(self, x, cls):
|
||||
return self.super_as_input(super(cls, self), x)
|
||||
|
||||
|
||||
class TestSuperAsInput2(TestCaseBase):
|
||||
def test_super_as_input(self):
|
||||
x = paddle.to_tensor(3)
|
||||
self.assert_results(
|
||||
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputC
|
||||
)
|
||||
self.assert_results(
|
||||
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputB
|
||||
)
|
||||
|
||||
def test_guard_run(self): # test guard
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
x = paddle.to_tensor(3)
|
||||
self.assert_results(
|
||||
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputC
|
||||
)
|
||||
self.assert_results(
|
||||
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputC
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
x = paddle.to_tensor(4)
|
||||
self.assert_results(
|
||||
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputB
|
||||
)
|
||||
self.assert_results(
|
||||
ClassSuperAsInputC().test_super_as_input, x, ClassSuperAsInputB
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
# ---------------------- test case which has no functions ----------------------
|
||||
class ClassWithAttributionA:
|
||||
a = 1
|
||||
|
||||
|
||||
class ClassWithAttributionB(ClassWithAttributionA):
|
||||
a = 111
|
||||
|
||||
|
||||
class ClassWithAttributionC(ClassWithAttributionB):
|
||||
@check_no_breakgraph
|
||||
def foo(self, x):
|
||||
return (
|
||||
super().a + x,
|
||||
super(ClassWithAttributionC, self).a + x, # noqa: UP008
|
||||
super(ClassWithAttributionB, self).a + x,
|
||||
)
|
||||
|
||||
|
||||
class TestSuperAttr(TestCaseBase):
|
||||
def test_attr_equal(self):
|
||||
x = paddle.to_tensor([4.0])
|
||||
self.assert_results(ClassWithAttributionC().foo, x)
|
||||
|
||||
def test_guard_run(self): # test guard
|
||||
x = paddle.to_tensor([4.0])
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(ClassWithAttributionC().foo, x)
|
||||
self.assert_results(ClassWithAttributionC().foo, x)
|
||||
self.assert_results(ClassWithAttributionC().foo, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
|
||||
# ---------------------- test case which has fake super ----------------------
|
||||
class Toy:
|
||||
@check_no_breakgraph
|
||||
def get(self, x):
|
||||
return x + 1
|
||||
|
||||
|
||||
class FakeSuperBase:
|
||||
@check_no_breakgraph
|
||||
def put(self, x):
|
||||
return x + 1
|
||||
|
||||
|
||||
class FakeSuperClass(FakeSuperBase):
|
||||
@check_no_breakgraph
|
||||
def fake_super_function(self, x):
|
||||
return super(1, 2).get(x)
|
||||
|
||||
def super_function_as_input(self, fn, x):
|
||||
return fn().put(x)
|
||||
|
||||
|
||||
# We create a fake `super` and inject it to `__globals__` of the function
|
||||
new_globals = FakeSuperClass.fake_super_function.__globals__.copy()
|
||||
new_globals["super"] = lambda x, y: Toy()
|
||||
|
||||
FakeSuperClass.fake_super_function = types.FunctionType(
|
||||
FakeSuperClass.fake_super_function.__code__,
|
||||
new_globals,
|
||||
name=FakeSuperClass.fake_super_function.__name__,
|
||||
argdefs=FakeSuperClass.fake_super_function.__defaults__,
|
||||
closure=FakeSuperClass.fake_super_function.__closure__,
|
||||
)
|
||||
|
||||
|
||||
class TestCustomSuper(TestCaseBase):
|
||||
def test_fake_super(self):
|
||||
self.assert_results(
|
||||
FakeSuperClass().fake_super_function, paddle.to_tensor(3.0)
|
||||
)
|
||||
|
||||
def test_super_function_as_input(self):
|
||||
if sys.version_info >= (3, 13):
|
||||
self.assert_exceptions(
|
||||
RuntimeError,
|
||||
r"super\(\): __class__ cell not found",
|
||||
FakeSuperClass().super_function_as_input,
|
||||
super,
|
||||
paddle.to_tensor(3.0),
|
||||
)
|
||||
if sys.version_info < (3, 13):
|
||||
self.assert_exceptions(
|
||||
InnerError,
|
||||
"KeyError: '__class__'",
|
||||
FakeSuperClass().super_function_as_input,
|
||||
super,
|
||||
paddle.to_tensor(3.0),
|
||||
)
|
||||
|
||||
|
||||
# ------ test SuperVariable setattr + getattr ------
|
||||
class LrClassBase:
|
||||
def __init__(self, last_lr, last_epoch):
|
||||
self.last_lr = last_lr
|
||||
self.last_epoch = last_epoch
|
||||
self.step()
|
||||
|
||||
def step(self):
|
||||
self.last_epoch += 1
|
||||
self.last_lr = self.get_lr()
|
||||
|
||||
def get_lr(self):
|
||||
return self.last_lr + 0.0001
|
||||
|
||||
def __call__(self) -> float:
|
||||
return self.last_lr
|
||||
|
||||
|
||||
class LrClassSub(LrClassBase):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(
|
||||
kwargs.get("last_lr", 0.01), kwargs.get("last_epoch", 0)
|
||||
)
|
||||
|
||||
|
||||
class TestSuperSetattrGetattr(Dy2StTestBase):
|
||||
def setUp(self):
|
||||
def dyfunc(lr_decay):
|
||||
lr = lr_decay()
|
||||
return paddle.to_tensor(lr)
|
||||
|
||||
lr_decay = LrClassSub(
|
||||
base_lr=0.1, verbose=True, last_lr=0.3, last_epoch=3
|
||||
)
|
||||
self.dygraph_func = lambda: dyfunc(lr_decay)
|
||||
|
||||
def get_dygraph_output(self):
|
||||
res = self.dygraph_func()
|
||||
return res
|
||||
|
||||
def get_static_output(self):
|
||||
static_res = paddle.jit.to_static(self.dygraph_func)()
|
||||
return static_res
|
||||
|
||||
@test_default_mode_only
|
||||
def test_transformed_static_result(self):
|
||||
dygraph_res = self.get_dygraph_output()
|
||||
static_res = self.get_static_output()
|
||||
np.testing.assert_allclose(dygraph_res, static_res, rtol=1e-05)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,978 @@
|
||||
# Copyright (c) 2025 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 sys
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
from paddle.jit.sot.opcode_translator.executor.opcode_executor import (
|
||||
ALREADY_SUPPORTED_EXCEPTION,
|
||||
)
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
NOT_ALLOW_FALLBACK = ALREADY_SUPPORTED_EXCEPTION
|
||||
|
||||
|
||||
class TestRaiseVarargs(TestCaseBase):
|
||||
# test `RAISE_VARARGS`
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def argc_equal_to_0_wo_exception(x):
|
||||
try:
|
||||
x += 1
|
||||
# In CPython, `RuntimeError` will be triggered at this point.
|
||||
# SOT have setup the exception stack and raise the exception manually.
|
||||
# This function is designed to test scenarios involving only the `raise` statement.
|
||||
raise # Bare `raise` statement is not inside an exception handler # noqa: PLE0704
|
||||
x /= 2
|
||||
except RuntimeError:
|
||||
x -= 3
|
||||
x *= 4
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def argc_equal_to_0_zero_div_err(x):
|
||||
x += 1
|
||||
try:
|
||||
try:
|
||||
x += 2
|
||||
result = 10 / 0
|
||||
except ZeroDivisionError:
|
||||
x += 3
|
||||
raise # RAISE_VARARGS(0)
|
||||
except:
|
||||
x += 4
|
||||
return x + 5
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def argc_equal_to_0_simulating_zero_div_err(x):
|
||||
x += 1
|
||||
try:
|
||||
try:
|
||||
x += 2
|
||||
raise ZeroDivisionError("")
|
||||
except ZeroDivisionError:
|
||||
x += 3
|
||||
raise # RAISE_VARARGS(0)
|
||||
except:
|
||||
x += 4
|
||||
return x + 5
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def argc_equal_to_1(x):
|
||||
x += 1
|
||||
try:
|
||||
try:
|
||||
x += 2
|
||||
except:
|
||||
x += 3
|
||||
else:
|
||||
x += 4
|
||||
raise NotImplementedError # RAISE_VARARGS(1)
|
||||
x += 5
|
||||
except:
|
||||
x += 6
|
||||
return x + 7
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def argc_equal_to_2(x):
|
||||
x -= 10
|
||||
try:
|
||||
try:
|
||||
x -= 300
|
||||
finally:
|
||||
x -= 400
|
||||
raise ValueError from None # RAISE_VARARGS(2)
|
||||
except ValueError:
|
||||
x -= 500
|
||||
|
||||
return x - 600
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def argc_equal_to_1_2(x):
|
||||
try:
|
||||
x += 1
|
||||
try:
|
||||
x /= 2
|
||||
raise NameError # RAISE_VARARGS(1)
|
||||
x *= 3
|
||||
except NameError as e:
|
||||
x -= 4
|
||||
raise TimeoutError("TESTING") from e # RAISE_VARARGS(2)
|
||||
except:
|
||||
x /= 5
|
||||
return x + 6
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def argc_equal_to_1_0(x):
|
||||
try:
|
||||
try:
|
||||
x -= 1
|
||||
raise ValueError("TESTING") # RAISE_VARARGS(1)
|
||||
x += 2
|
||||
except NotImplementedError:
|
||||
x /= 3
|
||||
raise # RAISE_VARARGS(0)
|
||||
except (KeyError, IndexError):
|
||||
x *= 4
|
||||
except ValueError:
|
||||
x += 5
|
||||
return x
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_RAISE_VARARGS_argc(self):
|
||||
self.assert_results(
|
||||
self.argc_equal_to_0_wo_exception, paddle.to_tensor(0.01)
|
||||
)
|
||||
self.assert_results(
|
||||
self.argc_equal_to_0_zero_div_err, paddle.to_tensor(0.02)
|
||||
)
|
||||
self.assert_results(
|
||||
self.argc_equal_to_0_simulating_zero_div_err, paddle.to_tensor(0.03)
|
||||
)
|
||||
self.assert_results(self.argc_equal_to_1, paddle.to_tensor(0.04))
|
||||
self.assert_results(self.argc_equal_to_2, paddle.to_tensor(0.05))
|
||||
self.assert_results(self.argc_equal_to_1_2, paddle.to_tensor(0.06))
|
||||
self.assert_results(self.argc_equal_to_1_0, paddle.to_tensor(0.07))
|
||||
|
||||
|
||||
class TestException(TestCaseBase):
|
||||
@staticmethod
|
||||
def create_builtin_exception(x):
|
||||
def identity(e):
|
||||
return e
|
||||
|
||||
x += 1
|
||||
value_error = ValueError()
|
||||
identity(value_error)
|
||||
x += 2
|
||||
type_error = TypeError("")
|
||||
identity(type_error)
|
||||
x += 3
|
||||
key_error = KeyError("")
|
||||
identity(key_error)
|
||||
x += 4
|
||||
exception = Exception("")
|
||||
identity(exception)
|
||||
x += 5
|
||||
unicode_translate_error = UnicodeTranslateError("", -1, -1, "")
|
||||
identity(unicode_translate_error)
|
||||
x += 6
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
def create_user_defined_exception(x):
|
||||
# TODO: Need to support user-defined exception
|
||||
return x
|
||||
|
||||
@check_no_breakgraph
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_dispatch(self):
|
||||
self.assert_results(
|
||||
self.create_builtin_exception, paddle.to_tensor(111.0)
|
||||
)
|
||||
self.assert_results(
|
||||
self.create_user_defined_exception, paddle.to_tensor(222.0)
|
||||
)
|
||||
|
||||
|
||||
class TestTryExcept(TestCaseBase):
|
||||
# try ... except ...
|
||||
# ---------------- test raising exception directly ----------------
|
||||
@staticmethod
|
||||
def raise_value_error_obj():
|
||||
raise ValueError("Test whether raising `ValueError`")
|
||||
|
||||
@staticmethod
|
||||
def raise_value_error_cls():
|
||||
raise ValueError
|
||||
|
||||
@staticmethod
|
||||
def raise_asserterror(x):
|
||||
assert x, "Test AssertionError"
|
||||
|
||||
# Since the exceptions are not handled, fallback is permitted.
|
||||
@strict_mode_guard(False)
|
||||
def test_exception_raising(self):
|
||||
with self.assertRaisesRegex(
|
||||
ValueError, "Test whether raising `ValueError`"
|
||||
):
|
||||
symbolic_translate(self.raise_value_error_obj)()
|
||||
|
||||
with self.assertRaisesRegex(ValueError, ""):
|
||||
symbolic_translate(self.raise_value_error_cls)()
|
||||
|
||||
with self.assertRaisesRegex(AssertionError, "Test AssertionError"):
|
||||
symbolic_translate(self.raise_asserterror)(False)
|
||||
|
||||
with self.assertRaisesRegex(AssertionError, "Test AssertionError"):
|
||||
symbolic_translate(self.raise_asserterror)(paddle.to_tensor(0))
|
||||
|
||||
# ---------------- without error ----------------
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_wo_error(x):
|
||||
try:
|
||||
x = x + 1
|
||||
except:
|
||||
x = x * 2
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_exception_wo_error(x):
|
||||
try:
|
||||
x = x + 1
|
||||
except Exception:
|
||||
x = x * 2
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_exception_as_e_wo_error(x):
|
||||
try:
|
||||
x = x + 1
|
||||
except Exception as e:
|
||||
x = x * 2
|
||||
return x
|
||||
|
||||
# ---------------- with error ----------------
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_with_error_obj(x):
|
||||
y = x + 3
|
||||
try:
|
||||
x = x + 1
|
||||
raise ValueError(f"{__class__.__name__}")
|
||||
x = x * 3
|
||||
except:
|
||||
y = x * 2
|
||||
return y
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_with_error_cls(x):
|
||||
y = x + 3
|
||||
try:
|
||||
x = x + 1
|
||||
raise ValueError
|
||||
x = x * 3
|
||||
except:
|
||||
y = x * 2
|
||||
return y
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_exception_with_error(x):
|
||||
# test `JUMP_IF_NOT_EXC_MATCH`
|
||||
x = x + 3
|
||||
try:
|
||||
x = x + 1
|
||||
raise ValueError("TESTING!")
|
||||
x = x * 3
|
||||
except Exception:
|
||||
x = x * 2
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_exception_as_e_with_error(x):
|
||||
# test `JUMP_IF_NOT_EXC_MATCH`
|
||||
y = x + 3
|
||||
try:
|
||||
x = x + 1
|
||||
raise ValueError("TESTING!")
|
||||
x = x * 3
|
||||
except ValueError as e:
|
||||
y = x * 2
|
||||
return y
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_exception_as_e_with_error_tuple(x):
|
||||
# test `JUMP_IF_NOT_EXC_MATCH`
|
||||
y = x + 3
|
||||
try:
|
||||
x = x + 1
|
||||
raise ValueError("TESTING!")
|
||||
x = x * 3
|
||||
except (ValueError, KeyError, NotImplementedError) as e:
|
||||
y = x * 2
|
||||
return y
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_exception_as_e_with_unmatched_error(x):
|
||||
# test `JUMP_IF_NOT_EXC_MATCH`
|
||||
y = x + 3
|
||||
try:
|
||||
x = x + 1
|
||||
raise ValueError("TESTING!")
|
||||
x = x * 3
|
||||
except KeyError as e:
|
||||
y = x * 2
|
||||
return y + 3
|
||||
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_except_exception_as_e_with_matched_error_reraise(x):
|
||||
# test `JUMP_IF_NOT_EXC_MATCH`
|
||||
y = x + 3
|
||||
try:
|
||||
x = x + 1
|
||||
raise IndexError("TESTING!")
|
||||
x = x * 3
|
||||
except IndexError as e:
|
||||
y = x * 2
|
||||
raise LookupError("TESTING!")
|
||||
return y + 3
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_try_except(self):
|
||||
self.assert_results(self.try_except_wo_error, paddle.to_tensor(2))
|
||||
self.assert_results(
|
||||
self.try_except_exception_wo_error, paddle.to_tensor(3)
|
||||
)
|
||||
self.assert_results(
|
||||
self.try_except_exception_as_e_wo_error, paddle.to_tensor(4)
|
||||
)
|
||||
self.assert_results(self.try_except_with_error_obj, paddle.to_tensor(5))
|
||||
self.assert_results(self.try_except_with_error_cls, paddle.to_tensor(6))
|
||||
self.assert_results(
|
||||
self.try_except_exception_with_error, paddle.to_tensor(7)
|
||||
)
|
||||
self.assert_results(
|
||||
self.try_except_exception_as_e_with_error, paddle.to_tensor(8)
|
||||
)
|
||||
self.assert_results(
|
||||
self.try_except_exception_as_e_with_error_tuple, paddle.to_tensor(9)
|
||||
)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_error(self):
|
||||
# RERAISE
|
||||
self.assert_exceptions(
|
||||
ValueError,
|
||||
"TESTING!",
|
||||
self.try_except_exception_as_e_with_unmatched_error,
|
||||
paddle.to_tensor(0.001),
|
||||
)
|
||||
|
||||
self.assert_exceptions(
|
||||
LookupError,
|
||||
"TESTING!",
|
||||
self.try_except_exception_as_e_with_matched_error_reraise,
|
||||
paddle.to_tensor(0.001),
|
||||
)
|
||||
|
||||
|
||||
class TestTryFinally(TestCaseBase):
|
||||
# try ... finally ...
|
||||
# ---------------- without error ----------------
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_finally_wo_error(x):
|
||||
try:
|
||||
x = 1 + x
|
||||
finally:
|
||||
x *= 2
|
||||
return x
|
||||
|
||||
# ---------------- with error ----------------
|
||||
@staticmethod
|
||||
@check_no_breakgraph
|
||||
def try_finally_with_error_but_return_in_finally(x):
|
||||
# RERAISE
|
||||
try:
|
||||
x = 3 + x
|
||||
raise NotImplementedError("TESTING!")
|
||||
x = 300 + x
|
||||
finally:
|
||||
x *= 2
|
||||
# `return` inside `finally` blocks cause exceptions to be silenced
|
||||
return x # noqa: B012
|
||||
|
||||
@staticmethod
|
||||
def try_finally_with_error(x):
|
||||
# RERAISE
|
||||
try:
|
||||
x = 3 + x
|
||||
raise NotImplementedError("TESTING!")
|
||||
x = 300 + x
|
||||
finally:
|
||||
x *= 2
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
def try_finally_with_error_in_finally(x):
|
||||
# RERAISE
|
||||
try:
|
||||
x = 3 + x
|
||||
return x
|
||||
finally:
|
||||
x *= 2
|
||||
raise TimeoutError("TESTING!")
|
||||
x = 300 + x
|
||||
return x
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_try_finally(self):
|
||||
self.assert_results(self.try_finally_wo_error, paddle.to_tensor(14))
|
||||
self.assert_results(
|
||||
self.try_finally_with_error_but_return_in_finally,
|
||||
paddle.to_tensor(15),
|
||||
)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_error(self):
|
||||
# RERAISE
|
||||
self.assert_exceptions(
|
||||
NotImplementedError,
|
||||
"TESTING!",
|
||||
self.try_finally_with_error,
|
||||
paddle.to_tensor(16),
|
||||
)
|
||||
self.assert_exceptions(
|
||||
TimeoutError,
|
||||
"TESTING!",
|
||||
self.try_finally_with_error_in_finally,
|
||||
paddle.to_tensor(17),
|
||||
)
|
||||
|
||||
|
||||
class TestTryExceptElse(TestCaseBase):
|
||||
# try ... except ... else
|
||||
# `else` is useful for code that must be executed if the try clause does not raise an exception.
|
||||
|
||||
# ---------------- without error ----------------
|
||||
@staticmethod
|
||||
def try_except_else(x):
|
||||
try:
|
||||
x += 1
|
||||
except:
|
||||
x += 2
|
||||
else:
|
||||
x += 3
|
||||
return x
|
||||
|
||||
# ---------------- with error ----------------
|
||||
@staticmethod
|
||||
def try_except_else_except_with_matched_error(x):
|
||||
try:
|
||||
x += 4
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
x += 5
|
||||
else:
|
||||
x += 6
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@strict_mode_guard(False)
|
||||
def try_except_else_except_with_mismatched_error(x):
|
||||
try:
|
||||
x += 4
|
||||
raise TimeoutError
|
||||
except KeyError:
|
||||
x += 5
|
||||
else:
|
||||
x += 6
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
def try_except_else_error_in_except(x):
|
||||
try:
|
||||
x += 4
|
||||
except KeyError:
|
||||
x += 5
|
||||
raise ValueError
|
||||
else:
|
||||
x += 6
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@strict_mode_guard(False)
|
||||
def try_except_else_error_in_else(x):
|
||||
try:
|
||||
x += 4
|
||||
except KeyError:
|
||||
x += 5
|
||||
else:
|
||||
x += 6
|
||||
raise ValueError("Testing!")
|
||||
return x
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_try_except_else(self):
|
||||
# self.assert_results(self.try_except_else, paddle.to_tensor(14))
|
||||
self.assert_results(
|
||||
self.try_except_else_except_with_matched_error, paddle.to_tensor(15)
|
||||
)
|
||||
# self.assert_results(
|
||||
# self.try_except_else_error_in_except, paddle.to_tensor(16)
|
||||
# )
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_error(self):
|
||||
# RERAISE
|
||||
self.assert_exceptions(
|
||||
TimeoutError,
|
||||
"",
|
||||
self.try_except_else_except_with_mismatched_error,
|
||||
paddle.to_tensor(0.001),
|
||||
)
|
||||
self.assert_exceptions(
|
||||
ValueError,
|
||||
"Testing!",
|
||||
self.try_except_else_error_in_else,
|
||||
paddle.to_tensor(0.002),
|
||||
)
|
||||
|
||||
|
||||
class TestTryExceptFinally(TestCaseBase):
|
||||
# try ... except ... finally
|
||||
# ---------------- without error ----------------
|
||||
@staticmethod
|
||||
def try_except_finally(x):
|
||||
try:
|
||||
x -= 1
|
||||
except:
|
||||
x -= 2
|
||||
finally:
|
||||
x -= 3
|
||||
return x
|
||||
|
||||
# ---------------- without error ----------------
|
||||
@staticmethod
|
||||
def try_except_finally_with_matched_exception(x):
|
||||
try:
|
||||
x -= 1
|
||||
raise ValueError
|
||||
except:
|
||||
x -= 2
|
||||
finally:
|
||||
x -= 3
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@strict_mode_guard(False)
|
||||
def try_except_finally_with_mismatched_exception(x):
|
||||
try:
|
||||
x -= 1
|
||||
raise ValueError("TESTING")
|
||||
except AttributeError:
|
||||
x -= 2
|
||||
finally:
|
||||
x -= 3
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
def try_except_finally_in_except(x):
|
||||
try:
|
||||
x -= 1
|
||||
except AttributeError:
|
||||
x -= 2
|
||||
raise ValueError
|
||||
finally:
|
||||
x -= 3
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@strict_mode_guard(False)
|
||||
def try_except_finally_in_finally(x):
|
||||
try:
|
||||
x -= 1
|
||||
except AttributeError:
|
||||
x -= 2
|
||||
finally:
|
||||
x -= 3
|
||||
raise ValueError
|
||||
return x
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_try_except_finally(self):
|
||||
self.assert_results(self.try_except_finally, paddle.to_tensor([0.11]))
|
||||
self.assert_results(
|
||||
self.try_except_finally_with_matched_exception,
|
||||
paddle.to_tensor([0.22]),
|
||||
)
|
||||
self.assert_results(
|
||||
self.try_except_finally_in_except,
|
||||
paddle.to_tensor([0.33]),
|
||||
)
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_error(self):
|
||||
# RERAISE
|
||||
self.assert_exceptions(
|
||||
ValueError,
|
||||
"TESTING",
|
||||
self.try_except_finally_with_mismatched_exception,
|
||||
paddle.to_tensor(0.001),
|
||||
)
|
||||
|
||||
self.assert_exceptions(
|
||||
ValueError,
|
||||
"",
|
||||
self.try_except_finally_in_finally,
|
||||
paddle.to_tensor(0.001),
|
||||
)
|
||||
|
||||
|
||||
class TestTryExceptElseFinally(TestCaseBase):
|
||||
# try ... except ... else ... finally
|
||||
# ---------------- without error ----------------
|
||||
@staticmethod
|
||||
def try_except_else_finally(x):
|
||||
try:
|
||||
x -= 1
|
||||
except:
|
||||
x -= 2
|
||||
else:
|
||||
x -= 3
|
||||
finally:
|
||||
x -= 4
|
||||
return x
|
||||
|
||||
# ---------------- with error ----------------
|
||||
@staticmethod
|
||||
def try_except_else_finally_with_matched_exception(x):
|
||||
try:
|
||||
x -= 1
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
x -= 2
|
||||
else:
|
||||
x -= 3
|
||||
finally:
|
||||
x -= 4
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@strict_mode_guard(False)
|
||||
def try_except_else_finally_with_mismatched_exception(x):
|
||||
try:
|
||||
x -= 1
|
||||
raise SystemError("TESTING")
|
||||
except NotImplementedError:
|
||||
x -= 2
|
||||
else:
|
||||
x -= 3
|
||||
finally:
|
||||
x -= 4
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@strict_mode_guard(False)
|
||||
def try_except_else_finally_with_exception_in_else(x):
|
||||
try:
|
||||
x -= 1
|
||||
except NotImplementedError:
|
||||
x -= 2
|
||||
else:
|
||||
x -= 3
|
||||
raise ModuleNotFoundError("TESTING")
|
||||
finally:
|
||||
x -= 4
|
||||
return x
|
||||
|
||||
@staticmethod
|
||||
@strict_mode_guard(False)
|
||||
def try_except_else_finally_with_exception_in_finally(x):
|
||||
try:
|
||||
x -= 1
|
||||
except NotImplementedError:
|
||||
x -= 2
|
||||
else:
|
||||
x -= 3
|
||||
finally:
|
||||
x -= 4
|
||||
raise SyntaxError("TESTING")
|
||||
return x
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_try_except_finally(self):
|
||||
self.assert_results(
|
||||
self.try_except_else_finally, paddle.to_tensor([0.11])
|
||||
)
|
||||
self.assert_results(
|
||||
self.try_except_else_finally_with_matched_exception,
|
||||
paddle.to_tensor([0.22]),
|
||||
)
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_error(self):
|
||||
# RERAISE
|
||||
self.assert_exceptions(
|
||||
SystemError,
|
||||
"TESTING",
|
||||
self.try_except_else_finally_with_mismatched_exception,
|
||||
paddle.to_tensor(0.001),
|
||||
)
|
||||
self.assert_exceptions(
|
||||
ModuleNotFoundError,
|
||||
"TESTING",
|
||||
self.try_except_else_finally_with_exception_in_else,
|
||||
paddle.to_tensor(0.001),
|
||||
)
|
||||
self.assert_exceptions(
|
||||
SyntaxError,
|
||||
"TESTING",
|
||||
self.try_except_else_finally_with_exception_in_finally,
|
||||
paddle.to_tensor(0.001),
|
||||
)
|
||||
|
||||
|
||||
class TestNestingCase(TestCaseBase):
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
@check_no_breakgraph
|
||||
def test_try_nesting(self):
|
||||
def try_nesting_wo_error(x):
|
||||
try:
|
||||
try:
|
||||
try:
|
||||
try:
|
||||
try:
|
||||
try:
|
||||
x -= 1
|
||||
raise ValueError(
|
||||
"TESTING"
|
||||
) # RAISE_VARARGS(1)
|
||||
x += 2
|
||||
except NotImplementedError:
|
||||
x /= 3
|
||||
raise # RAISE_VARARGS(0)
|
||||
except (KeyError, IndexError):
|
||||
x *= 4
|
||||
except ValueError:
|
||||
x += 5
|
||||
raise NameError # RAISE_VARARGS(1)
|
||||
except SyntaxError:
|
||||
x /= 6
|
||||
except (TypeError, FileNotFoundError, NameError) as e:
|
||||
x -= 7
|
||||
raise TimeoutError(
|
||||
"TESTING"
|
||||
) from e # RAISE_VARARGS(2)
|
||||
except:
|
||||
x /= 8
|
||||
raise AssertionError
|
||||
except IndentationError as e:
|
||||
x *= 9
|
||||
except AssertionError as e:
|
||||
x += 10
|
||||
raise # RAISE_VARARGS(0)
|
||||
except Exception as e:
|
||||
x /= 11
|
||||
|
||||
return x + 12
|
||||
|
||||
self.assert_results(try_nesting_wo_error, paddle.to_tensor(0.5))
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
@check_no_breakgraph
|
||||
def test_function_nesting(self):
|
||||
def raise_value_error_obj(x):
|
||||
x += 1
|
||||
raise ValueError("")
|
||||
|
||||
def raise_value_error_cls(x):
|
||||
x += 2
|
||||
raise ValueError
|
||||
|
||||
def raise_zero_div_error(x):
|
||||
x += 3
|
||||
return 19.0 / 0
|
||||
|
||||
def raise_assert_error(x):
|
||||
x += 4
|
||||
assert []
|
||||
|
||||
def raise_not_implemented_error(x):
|
||||
x += 5
|
||||
raise NotImplementedError
|
||||
|
||||
def one_nesting(x, func):
|
||||
x *= 6
|
||||
func(x)
|
||||
|
||||
def two_nesting(x, func):
|
||||
x /= 7
|
||||
one_nesting(x, func)
|
||||
|
||||
def three_nesting(x, func):
|
||||
x -= 8
|
||||
two_nesting(x, func)
|
||||
|
||||
def get_test_func(x, func=None):
|
||||
try:
|
||||
x += 1
|
||||
try:
|
||||
x /= 2
|
||||
three_nesting(x, func)
|
||||
x -= 3
|
||||
except ValueError:
|
||||
x *= 4
|
||||
except:
|
||||
x += 5
|
||||
return x # / 6
|
||||
|
||||
self.assert_results(
|
||||
get_test_func, paddle.to_tensor(0.3), raise_value_error_obj
|
||||
)
|
||||
self.assert_results(
|
||||
get_test_func, paddle.to_tensor(0.4), raise_value_error_cls
|
||||
)
|
||||
self.assert_results(
|
||||
get_test_func, paddle.to_tensor(0.5), raise_zero_div_error
|
||||
)
|
||||
self.assert_results(
|
||||
get_test_func, paddle.to_tensor(0.6), raise_assert_error
|
||||
)
|
||||
self.assert_results(
|
||||
get_test_func, paddle.to_tensor(0.7), raise_not_implemented_error
|
||||
)
|
||||
|
||||
|
||||
class TestAssertException(TestCaseBase):
|
||||
@staticmethod
|
||||
def try_assert(x, condition):
|
||||
# test py value or paddle tensor value as condition
|
||||
try:
|
||||
x += 1
|
||||
try:
|
||||
x /= 2
|
||||
raise TimeoutError("TESTING")
|
||||
except:
|
||||
x -= 3
|
||||
assert condition
|
||||
except:
|
||||
x *= 4
|
||||
return x / 5
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_assert_with_py_var_as_condition(self):
|
||||
# Test the case where `condition` is Python variable
|
||||
self.assert_results(self.try_assert, paddle.to_tensor(1), False)
|
||||
self.assert_results(self.try_assert, paddle.to_tensor(2), True)
|
||||
self.assert_results(self.try_assert, paddle.to_tensor(3), [])
|
||||
self.assert_results(self.try_assert, paddle.to_tensor(4), [1])
|
||||
self.assert_results(self.try_assert, paddle.to_tensor(5), "")
|
||||
self.assert_results(self.try_assert, paddle.to_tensor(6), "QAQ")
|
||||
# TODO(DrRyanHuang): The following two cases are not supported yet.
|
||||
# self.assert_results(self.try_assert, paddle.to_tensor(7), ValueError)
|
||||
# self.assert_results(self.try_assert, paddle.to_tensor(8), ValueError())
|
||||
|
||||
# Currently, since the assert statement is essentially an if statement and can cause breakgraph,
|
||||
# using a Tensor as a condition is not supported. Therefore, fallback is allowed.
|
||||
@strict_mode_guard(False)
|
||||
def test_assert_with_tensor_as_condition(self):
|
||||
# Test the case where `condition` is Paddle Tensor
|
||||
self.assert_results(
|
||||
self.try_assert, paddle.to_tensor(8), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
self.try_assert, paddle.to_tensor(9), paddle.to_tensor(0)
|
||||
)
|
||||
self.assert_results(
|
||||
self.try_assert, paddle.to_tensor(10), paddle.to_tensor(-1)
|
||||
)
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_assert_true(self):
|
||||
@check_no_breakgraph
|
||||
def try_assert_except(x, y):
|
||||
x += 1
|
||||
try:
|
||||
x += 2
|
||||
assert y > -10000
|
||||
x += 3
|
||||
except:
|
||||
x += 4
|
||||
|
||||
self.assert_results(try_assert_except, paddle.to_tensor(10), 10)
|
||||
|
||||
@strict_mode_guard(NOT_ALLOW_FALLBACK)
|
||||
def test_assert_false(self):
|
||||
@check_no_breakgraph
|
||||
def try_assert_except(x, y):
|
||||
try:
|
||||
x += 5
|
||||
assert y < -10000
|
||||
except AssertionError:
|
||||
x += 6
|
||||
|
||||
return x
|
||||
|
||||
self.assert_results(try_assert_except, paddle.to_tensor(10), 10)
|
||||
|
||||
|
||||
class TestGuard(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
@check_no_breakgraph
|
||||
def test_guard_run(self):
|
||||
def fn():
|
||||
try:
|
||||
paddle.jit.sot.psdb.breakgraph()
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
return True
|
||||
return False
|
||||
|
||||
self.assert_results(fn)
|
||||
|
||||
|
||||
class TestBuiltinFunctionRaiseExceptionGuard(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_guard_run(self):
|
||||
def foo_floordiv(x):
|
||||
1 / x
|
||||
|
||||
def foo_mod(x):
|
||||
2 % x
|
||||
|
||||
self.assert_results(foo_floordiv, 1)
|
||||
self.assert_exceptions(
|
||||
ZeroDivisionError,
|
||||
"division by zero",
|
||||
foo_floordiv,
|
||||
0,
|
||||
)
|
||||
self.assert_results(foo_mod, 10)
|
||||
if sys.version_info >= (3, 14):
|
||||
zero_mod_msg = "division by zero"
|
||||
else:
|
||||
zero_mod_msg = "integer (.)*modulo by zero"
|
||||
self.assert_exceptions(
|
||||
ZeroDivisionError,
|
||||
zero_mod_msg,
|
||||
foo_mod,
|
||||
0,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,138 @@
|
||||
# Copyright (c) 2025 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
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils.exceptions import FallbackError
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_math_model():
|
||||
import math
|
||||
|
||||
return math.sqrt(4)
|
||||
|
||||
|
||||
def import_relative():
|
||||
from . import test_case_base
|
||||
|
||||
return test_case_base
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_paddle_model(x: int):
|
||||
import paddle
|
||||
|
||||
return paddle.zeros([2, 3]) + x
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_os_model():
|
||||
import os
|
||||
|
||||
return os.name
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_sys_version():
|
||||
from sys import version
|
||||
|
||||
return version[:5] # Return first 5 chars to check import
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_paddle_nn():
|
||||
import paddle.nn
|
||||
|
||||
return paddle.nn.Layer.__name__
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_paddle_nn_from():
|
||||
from paddle import nn
|
||||
|
||||
return nn.Layer.__name__
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_paddle_nn_functional():
|
||||
import paddle.nn.functional as F
|
||||
|
||||
return F.relu.__name__
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_paddle_nn_linear():
|
||||
from paddle.nn import Linear
|
||||
|
||||
return Linear.__name__
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_collections():
|
||||
import collections
|
||||
|
||||
return collections.defaultdict.__name__
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_collections_defaultdict():
|
||||
from collections import defaultdict
|
||||
|
||||
return defaultdict.__name__
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_multiple_modules():
|
||||
import os
|
||||
import sys
|
||||
|
||||
return os.name + sys.version[:3]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def import_paddle_nn_linear_as():
|
||||
from paddle.nn import Linear as Lin
|
||||
|
||||
return Lin.__name__
|
||||
|
||||
|
||||
class TestImportModel(TestCaseBase):
|
||||
def test_import_model(self):
|
||||
self.assert_results(import_math_model)
|
||||
self.assert_results(import_paddle_model, 1)
|
||||
self.assert_results(import_os_model)
|
||||
self.assert_results(import_sys_version)
|
||||
self.assert_results(import_paddle_nn)
|
||||
self.assert_results(import_paddle_nn_from)
|
||||
self.assert_results(import_paddle_nn_functional)
|
||||
self.assert_results(import_paddle_nn_linear)
|
||||
self.assert_results(import_collections)
|
||||
self.assert_results(import_collections_defaultdict)
|
||||
self.assert_results(import_multiple_modules)
|
||||
self.assert_results(import_paddle_nn_linear_as)
|
||||
|
||||
def test_relative_import_error(self):
|
||||
self.assert_exceptions(
|
||||
FallbackError,
|
||||
"relative import with no known parent package",
|
||||
import_relative,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,248 @@
|
||||
# Copyright (c) 2026 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
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
from paddle.jit.sot import psdb, symbolic_translate # noqa: F401
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph # noqa: F401
|
||||
from paddle.jit.sot.utils.envs import strict_mode_guard
|
||||
from paddle.jit.sot.utils.exceptions import InnerError
|
||||
|
||||
try:
|
||||
from string.templatelib import Interpolation, Template
|
||||
except Exception: # pragma: no cover - env without t-string support
|
||||
Interpolation = None
|
||||
Template = None
|
||||
|
||||
|
||||
def _tstring_supported():
|
||||
if Template is None or Interpolation is None:
|
||||
return False
|
||||
try:
|
||||
compile("x = t'hello'", "<tstring>", "exec")
|
||||
except SyntaxError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _tstring_skip(*_args, **_kwargs):
|
||||
pass
|
||||
|
||||
|
||||
if _tstring_supported():
|
||||
_tstring_ns = {}
|
||||
exec(
|
||||
"""
|
||||
@check_no_breakgraph
|
||||
def test_t_literal():
|
||||
name = "world"
|
||||
return t"hello, {name}!"
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_t_with_expression():
|
||||
left = 2
|
||||
right = 5
|
||||
return t"{left} + {right} = {left + right}"
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_t_with_conversion_and_format():
|
||||
value = 3.14159
|
||||
return t"value={value!r:.2f}"
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_t_in_containers():
|
||||
prefix = "id"
|
||||
first = t"{prefix}-{1}"
|
||||
second = t"{prefix}-{2!a}"
|
||||
return [first, {"second": second}]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_t_with_no_interpolation():
|
||||
return t"plain literal"
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_t_multiple_interpolations():
|
||||
a = 1
|
||||
b = 2
|
||||
c = 3
|
||||
return t"{a},{b},{c}"
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_t_with_format_spec_expression():
|
||||
value = 12.3456
|
||||
precision = 3
|
||||
return t"value={value:.{precision}f}"
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_t_with_ascii_conversion():
|
||||
text = "中文"
|
||||
return t"ascii={text!a}"
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_t_with_str_conversion():
|
||||
value = "hello"
|
||||
return t"str={value!s}"
|
||||
|
||||
|
||||
def test_t_with_fallback_not_recursive():
|
||||
psdb.fallback(recursive=False)
|
||||
value = "hello"
|
||||
return t"fallback={value!s}"
|
||||
|
||||
|
||||
def test_t_with_fallback_recursive():
|
||||
psdb.fallback(recursive=True)
|
||||
value = "hello"
|
||||
return t"fallback={value!s}"
|
||||
|
||||
|
||||
@psdb.check_no_fallback
|
||||
def test_t_with_forbidden_fallback():
|
||||
psdb.fallback(recursive=False)
|
||||
value = "hello"
|
||||
return t"fallback={value!s}"
|
||||
""",
|
||||
globals(),
|
||||
_tstring_ns,
|
||||
)
|
||||
test_t_literal = _tstring_ns["test_t_literal"]
|
||||
test_t_with_expression = _tstring_ns["test_t_with_expression"]
|
||||
test_t_with_conversion_and_format = _tstring_ns[
|
||||
"test_t_with_conversion_and_format"
|
||||
]
|
||||
test_t_in_containers = _tstring_ns["test_t_in_containers"]
|
||||
test_t_with_no_interpolation = _tstring_ns["test_t_with_no_interpolation"]
|
||||
test_t_multiple_interpolations = _tstring_ns[
|
||||
"test_t_multiple_interpolations"
|
||||
]
|
||||
test_t_with_format_spec_expression = _tstring_ns[
|
||||
"test_t_with_format_spec_expression"
|
||||
]
|
||||
test_t_with_ascii_conversion = _tstring_ns["test_t_with_ascii_conversion"]
|
||||
test_t_with_str_conversion = _tstring_ns["test_t_with_str_conversion"]
|
||||
test_t_with_fallback_not_recursive = _tstring_ns[
|
||||
"test_t_with_fallback_not_recursive"
|
||||
]
|
||||
test_t_with_fallback_recursive = _tstring_ns[
|
||||
"test_t_with_fallback_recursive"
|
||||
]
|
||||
test_t_with_forbidden_fallback = _tstring_ns[
|
||||
"test_t_with_forbidden_fallback"
|
||||
]
|
||||
else:
|
||||
test_t_literal = _tstring_skip
|
||||
test_t_with_expression = _tstring_skip
|
||||
test_t_with_conversion_and_format = _tstring_skip
|
||||
test_t_in_containers = _tstring_skip
|
||||
test_t_with_no_interpolation = _tstring_skip
|
||||
test_t_multiple_interpolations = _tstring_skip
|
||||
test_t_with_format_spec_expression = _tstring_skip
|
||||
test_t_with_ascii_conversion = _tstring_skip
|
||||
test_t_with_str_conversion = _tstring_skip
|
||||
test_t_with_fallback_not_recursive = _tstring_skip
|
||||
test_t_with_fallback_recursive = _tstring_skip
|
||||
test_t_with_forbidden_fallback = _tstring_skip
|
||||
|
||||
|
||||
class TestTString(TestCaseBase):
|
||||
def _assert_tstring_like(self, actual, expected):
|
||||
if Template is None or Interpolation is None:
|
||||
self.skipTest(
|
||||
"Template strings are not supported by this interpreter."
|
||||
)
|
||||
|
||||
self.assertIs(type(actual), type(expected))
|
||||
|
||||
if isinstance(actual, Template):
|
||||
self._assert_tstring_like(actual.strings, expected.strings)
|
||||
self._assert_tstring_like(
|
||||
actual.interpolations, expected.interpolations
|
||||
)
|
||||
return
|
||||
|
||||
if isinstance(actual, Interpolation):
|
||||
self._assert_tstring_like(actual.value, expected.value)
|
||||
self._assert_tstring_like(actual.expression, expected.expression)
|
||||
self.assertEqual(actual.conversion, expected.conversion)
|
||||
self.assertEqual(actual.format_spec, expected.format_spec)
|
||||
return
|
||||
|
||||
if isinstance(actual, (list, tuple)):
|
||||
self.assertEqual(len(actual), len(expected))
|
||||
for a_item, e_item in zip(actual, expected):
|
||||
self._assert_tstring_like(a_item, e_item)
|
||||
return
|
||||
|
||||
if isinstance(actual, dict):
|
||||
self.assertEqual(set(actual.keys()), set(expected.keys()))
|
||||
for key in actual:
|
||||
self._assert_tstring_like(actual[key], expected[key])
|
||||
return
|
||||
|
||||
if isinstance(actual, set):
|
||||
self.assertEqual(actual, expected)
|
||||
return
|
||||
|
||||
# Fallback to the generic nested matcher for tensors / arrays / scalars.
|
||||
self.assert_nest_match(actual, expected)
|
||||
|
||||
def assert_tstring_results(self, func, *args, **kwargs):
|
||||
sym_output = symbolic_translate(func)(*args, **kwargs)
|
||||
paddle_output = func(*args, **kwargs)
|
||||
self._assert_tstring_like(sym_output, paddle_output)
|
||||
|
||||
def test_symbolic_translate_handles_t_string(self):
|
||||
self.assert_tstring_results(test_t_literal)
|
||||
|
||||
def test_symbolic_translate_handles_formats_and_containers(self):
|
||||
self.assert_tstring_results(test_t_with_expression)
|
||||
self.assert_tstring_results(test_t_with_conversion_and_format)
|
||||
self.assert_tstring_results(test_t_in_containers)
|
||||
|
||||
def test_symbolic_translate_handles_more_cases(self):
|
||||
self.assert_tstring_results(test_t_with_no_interpolation)
|
||||
self.assert_tstring_results(test_t_multiple_interpolations)
|
||||
self.assert_tstring_results(test_t_with_format_spec_expression)
|
||||
self.assert_tstring_results(test_t_with_ascii_conversion)
|
||||
self.assert_tstring_results(test_t_with_str_conversion)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_tstring_fallback_not_recursive(self):
|
||||
self.assert_tstring_results(test_t_with_fallback_not_recursive)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_tstring_fallback_recursive(self):
|
||||
self.assert_tstring_results(test_t_with_fallback_recursive)
|
||||
|
||||
def test_tstring_check_no_fallback(self):
|
||||
if not _tstring_supported():
|
||||
self.skipTest(
|
||||
"Template strings are not supported by this interpreter."
|
||||
)
|
||||
with self.assertRaises(InnerError):
|
||||
symbolic_translate(test_t_with_forbidden_fallback)()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,259 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.opcode_translator.instruction_utils import (
|
||||
analysis_used_names,
|
||||
calc_offset_from_bytecode_offset,
|
||||
get_instructions,
|
||||
)
|
||||
from paddle.jit.sot.opcode_translator.instruction_utils.opcode_info import (
|
||||
PYOPCODE_CACHE_SIZE,
|
||||
)
|
||||
|
||||
|
||||
def assert_inputs_equals(instruction_offset: int, expected_inputs: set[str]):
|
||||
current_frame = inspect.currentframe()
|
||||
assert current_frame is not None
|
||||
test_frame = current_frame.f_back
|
||||
assert test_frame is not None
|
||||
|
||||
instructions = get_instructions(test_frame.f_code)
|
||||
current_offset = test_frame.f_lasti
|
||||
if sys.version_info >= (3, 13):
|
||||
current_offset += PYOPCODE_CACHE_SIZE.get("CALL") * 2
|
||||
current_instr_idx = calc_offset_from_bytecode_offset(
|
||||
current_offset + 2, instructions
|
||||
)
|
||||
reads, writes = analysis_used_names(
|
||||
instructions, current_instr_idx + instruction_offset
|
||||
)
|
||||
assert set(reads) == expected_inputs, (
|
||||
f"actual_inputs: {reads}, expected_inputs: {expected_inputs}"
|
||||
)
|
||||
|
||||
|
||||
def case1(x):
|
||||
m = x + 1
|
||||
n = x + 2
|
||||
assert_inputs_equals(0, {"x", "n"})
|
||||
y = x + 2
|
||||
assert_inputs_equals(0, {"n"})
|
||||
return n
|
||||
|
||||
|
||||
def case2(x):
|
||||
x = x + 1
|
||||
assert_inputs_equals(0, {"x"})
|
||||
y = x + 3
|
||||
z = x + y
|
||||
assert_inputs_equals(0, {"x"})
|
||||
x += 1
|
||||
m = x + 1
|
||||
n = x + m
|
||||
assert_inputs_equals(0, set())
|
||||
return 1
|
||||
|
||||
|
||||
def case3(x):
|
||||
y = x + 1
|
||||
|
||||
assert_inputs_equals(0, {"x"})
|
||||
if x:
|
||||
z = 1
|
||||
else:
|
||||
z = 2
|
||||
return z
|
||||
|
||||
|
||||
def case4(x):
|
||||
y = x + 1
|
||||
|
||||
assert_inputs_equals(0, {"x", "y"})
|
||||
if x:
|
||||
z = y
|
||||
else:
|
||||
z = x
|
||||
return z
|
||||
|
||||
|
||||
def case5(x):
|
||||
y = x + 1
|
||||
z = x + 2
|
||||
|
||||
assert_inputs_equals(0, {"z"})
|
||||
if z:
|
||||
a = 1
|
||||
else:
|
||||
b = 2
|
||||
return z
|
||||
|
||||
|
||||
def case6(x):
|
||||
y = x + 1
|
||||
z = x + 2
|
||||
|
||||
assert_inputs_equals(0, {"a", "z"})
|
||||
if z:
|
||||
a = 1
|
||||
else:
|
||||
a += 1
|
||||
return z
|
||||
|
||||
|
||||
def case7(x):
|
||||
y = x + 1
|
||||
z = x + 2
|
||||
|
||||
assert_inputs_equals(0, {"a", "z"})
|
||||
if not z:
|
||||
a += 1 # noqa: F821
|
||||
else:
|
||||
a = 1
|
||||
return z
|
||||
|
||||
|
||||
def breakgraph_api(x):
|
||||
return x
|
||||
|
||||
|
||||
def normal_api(x):
|
||||
return x
|
||||
|
||||
|
||||
def case8(x):
|
||||
x = normal_api(x)
|
||||
assert_inputs_equals(0, {"x"})
|
||||
for i in range(10):
|
||||
x += 1
|
||||
if i > 5:
|
||||
continue
|
||||
x += 10086
|
||||
x += i
|
||||
return x
|
||||
|
||||
|
||||
# NOTE(SigureMo): The offset should be between index of CALL instruction of assert_inputs_equals
|
||||
# and the index of the CALL instruction of breakgraph_api
|
||||
case9_offset = -7
|
||||
case9_offset = -9 if sys.version_info >= (3, 11) else case9_offset
|
||||
case9_offset = -6 if sys.version_info >= (3, 12) else case9_offset
|
||||
|
||||
|
||||
def case9(x):
|
||||
x = breakgraph_api(x)
|
||||
assert_inputs_equals(
|
||||
case9_offset, set()
|
||||
) # analysis when call breakgraph api (CALL_FUNCTION)
|
||||
for i in range(10):
|
||||
x += 1
|
||||
if i > 5:
|
||||
continue
|
||||
x += 10086
|
||||
x += i
|
||||
return x
|
||||
|
||||
|
||||
def case10(x):
|
||||
assert_inputs_equals(0, {"x", "y"})
|
||||
# if x == 0, y will be read before assignment
|
||||
for i in range(x):
|
||||
y = i
|
||||
z = y
|
||||
|
||||
return y + 1
|
||||
|
||||
|
||||
def case11(x):
|
||||
y = x + 1
|
||||
z = x + 2
|
||||
|
||||
assert_inputs_equals(0, {"a", "y", "z"})
|
||||
if z:
|
||||
if not y:
|
||||
a += 1 # noqa: F821
|
||||
else:
|
||||
a = 2
|
||||
else:
|
||||
if y:
|
||||
a = 1
|
||||
else:
|
||||
a += 1
|
||||
return z
|
||||
|
||||
|
||||
def case12(x):
|
||||
y = x + 1
|
||||
z = x + 2
|
||||
|
||||
assert_inputs_equals(0, {"a", "y", "z"})
|
||||
if z:
|
||||
if y:
|
||||
a = 2
|
||||
else:
|
||||
a += 2
|
||||
else:
|
||||
if y:
|
||||
a += 1
|
||||
else:
|
||||
a = 1
|
||||
return z
|
||||
|
||||
|
||||
class TestAnalysisInputs(unittest.TestCase):
|
||||
def test_case1(self):
|
||||
case1(paddle.to_tensor([1]))
|
||||
|
||||
def test_case2(self):
|
||||
case2(paddle.to_tensor([2]))
|
||||
|
||||
def test_case3(self):
|
||||
case3(paddle.to_tensor([3]))
|
||||
|
||||
def test_case4(self):
|
||||
case4(paddle.to_tensor([4]))
|
||||
|
||||
def test_case5(self):
|
||||
case5(paddle.to_tensor([5]))
|
||||
|
||||
def test_case6(self):
|
||||
case6(paddle.to_tensor([6]))
|
||||
|
||||
def test_case7(self):
|
||||
case7(paddle.to_tensor([7]))
|
||||
|
||||
def test_case8(self):
|
||||
case8(paddle.to_tensor([8]))
|
||||
|
||||
def test_case9(self):
|
||||
case9(paddle.to_tensor([9]))
|
||||
|
||||
def test_case10(self):
|
||||
case10(paddle.to_tensor([10]))
|
||||
|
||||
def test_case11(self):
|
||||
case11(paddle.to_tensor([11]))
|
||||
|
||||
def test_case12(self):
|
||||
case12(paddle.to_tensor([12]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,214 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.utils.paddle_api_config import add_break_graph_function
|
||||
|
||||
|
||||
def ifelse_func(x, y):
|
||||
if x > 0:
|
||||
y = y + 1
|
||||
else:
|
||||
y = y + 2
|
||||
return y
|
||||
|
||||
|
||||
class TestIfElse(TestCaseBase):
|
||||
def test_simple(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
y = paddle.to_tensor([2.0])
|
||||
self.assert_results(ifelse_func, x, y)
|
||||
|
||||
|
||||
def multi_output(x: paddle.Tensor):
|
||||
m = x + 1
|
||||
if x > 0:
|
||||
return m
|
||||
else:
|
||||
return 2 * m
|
||||
|
||||
|
||||
class TestBreakgraph(TestCaseBase):
|
||||
def test_simple(self):
|
||||
x = paddle.to_tensor(2)
|
||||
self.assert_results(multi_output, x)
|
||||
x = paddle.to_tensor(-2)
|
||||
self.assert_results(multi_output, x)
|
||||
|
||||
|
||||
def print_break_graph(x, y):
|
||||
z = x + y
|
||||
print(x, z)
|
||||
out = y * z * 2
|
||||
return out
|
||||
|
||||
|
||||
class TestPrint(TestCaseBase):
|
||||
def test_simple(self):
|
||||
x = paddle.to_tensor(2)
|
||||
y = paddle.to_tensor(3)
|
||||
self.assert_results(print_break_graph, x, y)
|
||||
|
||||
|
||||
def to_tensor_break_graph(x, y):
|
||||
z = x + y
|
||||
out = y * paddle.to_tensor(2) * z
|
||||
return out
|
||||
|
||||
|
||||
class TestToTensor(TestCaseBase):
|
||||
def test_simple(self):
|
||||
add_break_graph_function(paddle.to_tensor)
|
||||
x = paddle.to_tensor(2)
|
||||
y = paddle.to_tensor(3)
|
||||
self.assert_results(to_tensor_break_graph, x, y)
|
||||
|
||||
|
||||
def tensor_clear_gradient(x):
|
||||
x = paddle.to_tensor(x)
|
||||
x.clear_gradient()
|
||||
return x
|
||||
|
||||
|
||||
class TestBreakGraphInResumeFn(TestCaseBase):
|
||||
def test_simple(self):
|
||||
x = paddle.to_tensor(2)
|
||||
self.assert_results(tensor_clear_gradient, x)
|
||||
|
||||
|
||||
def inner_fn(a, b, c, d):
|
||||
return a + b * c - d
|
||||
|
||||
|
||||
def multi_stack_args(a, b, c):
|
||||
out = inner_fn(a, b, c, paddle.to_tensor(4))
|
||||
return out
|
||||
|
||||
|
||||
class TestMultiStackArgs(TestCaseBase):
|
||||
def test_simple(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
c = paddle.to_tensor(3)
|
||||
self.assert_results(multi_stack_args, a, b, c)
|
||||
|
||||
|
||||
def break_graph_in_call_method(x):
|
||||
out = paddle.nn.functional.relu(paddle.to_tensor([4.0]))
|
||||
return x + out
|
||||
|
||||
|
||||
def numpy_break_graph():
|
||||
a = paddle.to_tensor([1, 2])
|
||||
b = np.sum(a.numpy())
|
||||
print(b)
|
||||
return b
|
||||
|
||||
|
||||
class TestBreakGraphInCallMethod(TestCaseBase):
|
||||
def test_simple(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
break_graph_in_call_method(x)
|
||||
x = paddle.to_tensor([2.0])
|
||||
break_graph_in_call_method(x)
|
||||
|
||||
x = paddle.to_tensor([3.0])
|
||||
self.assert_results(break_graph_in_call_method, x)
|
||||
|
||||
def test_numpy(self):
|
||||
self.assert_results(numpy_break_graph)
|
||||
|
||||
|
||||
def test_break_graph_repeat(x):
|
||||
out = paddle.to_tensor(
|
||||
paddle.to_tensor(paddle.to_tensor(paddle.to_tensor([1.0])))
|
||||
)
|
||||
return x + out
|
||||
|
||||
|
||||
class TestBreakGraphRepeat(TestCaseBase):
|
||||
def test_simple(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
test_break_graph_repeat(x)
|
||||
x = paddle.to_tensor([2.0])
|
||||
test_break_graph_repeat(x)
|
||||
|
||||
x = paddle.to_tensor([3.0])
|
||||
self.assert_results(test_break_graph_repeat, x)
|
||||
|
||||
|
||||
def break_graph_resume_pass_null(x, y):
|
||||
return paddle.add(x, y[0:50] if y is not None else None)
|
||||
|
||||
|
||||
class TestBreakGraphResumePassNull(TestCaseBase):
|
||||
def test_break_graph_resume_pass_null(self):
|
||||
x = paddle.rand([50, 50], dtype=paddle.float32)
|
||||
y = paddle.rand([100, 50], dtype=paddle.float32)
|
||||
self.assert_results(break_graph_resume_pass_null, x, y)
|
||||
|
||||
|
||||
class MyLayer(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.head = paddle.nn.Linear(3, 10)
|
||||
|
||||
def forward_features(self, x):
|
||||
paddle.jit.sot.psdb.breakgraph()
|
||||
return x
|
||||
|
||||
def forward(self, x):
|
||||
x = self.forward_features(x)
|
||||
return self.head(x)
|
||||
|
||||
|
||||
class TestBreakGraphInLayer(TestCaseBase):
|
||||
def test_break_graph_in_layer(self):
|
||||
x = paddle.rand([2, 3], dtype=paddle.float32)
|
||||
net = MyLayer()
|
||||
self.assert_results(net.forward, x)
|
||||
|
||||
|
||||
def dummy(*args):
|
||||
return None
|
||||
|
||||
|
||||
def break_graph_call_generator_function(x):
|
||||
return dummy(y for y in x)
|
||||
|
||||
|
||||
class TestBreakGraphCallGeneratorFunction(TestCaseBase):
|
||||
def test_break_graph_when_call_generator_function(self):
|
||||
x = paddle.rand([1], dtype=paddle.float32)
|
||||
y = paddle.rand([1], dtype=paddle.float32)
|
||||
self.assert_results(break_graph_call_generator_function, [x, y])
|
||||
|
||||
|
||||
def unary_not_break_graph(x):
|
||||
return not x
|
||||
|
||||
|
||||
class TestUnaryNot(TestCaseBase):
|
||||
def test_unary_not_break_graph(self):
|
||||
x = paddle.to_tensor(0)
|
||||
self.assert_results(unary_not_break_graph, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import operator
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
class TestObject:
|
||||
pass
|
||||
|
||||
|
||||
class TestObjectWithBool:
|
||||
def __bool__(self):
|
||||
return False
|
||||
|
||||
|
||||
class TestObjectWithLen:
|
||||
def __init__(self, list):
|
||||
self.list = list
|
||||
|
||||
def __len__(self):
|
||||
return len(self.list)
|
||||
|
||||
|
||||
class TestObjectWithBoolAndLen:
|
||||
def __init__(self, list):
|
||||
self.list = list
|
||||
|
||||
def __bool__(self):
|
||||
return False
|
||||
|
||||
def __len__(self):
|
||||
return len(self.list)
|
||||
|
||||
|
||||
def call_bool_in_cond(obj):
|
||||
if obj:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def call_bool_by_bool(obj):
|
||||
return bool(obj)
|
||||
|
||||
|
||||
def call_bool_by_operator_truth(obj):
|
||||
return operator.truth(obj)
|
||||
|
||||
|
||||
class TestBuiltinBool(TestCaseBase):
|
||||
def test_object_disallow_breakgraph(self):
|
||||
call_bool_in_cond_no_breakgraph = check_no_breakgraph(call_bool_in_cond)
|
||||
call_bool_by_bool_no_breakgraph = check_no_breakgraph(call_bool_by_bool)
|
||||
call_bool_by_operator_truth_no_breakgraph = check_no_breakgraph(
|
||||
call_bool_by_operator_truth
|
||||
)
|
||||
|
||||
with test_instruction_translator_cache_context():
|
||||
obj = TestObject()
|
||||
self.assert_results(call_bool_in_cond_no_breakgraph, obj)
|
||||
self.assert_results(call_bool_by_bool_no_breakgraph, obj)
|
||||
self.assert_results(call_bool_by_operator_truth_no_breakgraph, obj)
|
||||
|
||||
with test_instruction_translator_cache_context():
|
||||
obj = TestObjectWithBool()
|
||||
self.assert_results(call_bool_in_cond_no_breakgraph, obj)
|
||||
self.assert_results(call_bool_by_bool_no_breakgraph, obj)
|
||||
self.assert_results(call_bool_by_operator_truth_no_breakgraph, obj)
|
||||
|
||||
with test_instruction_translator_cache_context():
|
||||
obj = TestObjectWithBoolAndLen([1, 2, 3])
|
||||
self.assert_results(call_bool_in_cond_no_breakgraph, obj)
|
||||
self.assert_results(call_bool_by_bool_no_breakgraph, obj)
|
||||
self.assert_results(call_bool_by_operator_truth_no_breakgraph, obj)
|
||||
|
||||
with test_instruction_translator_cache_context():
|
||||
obj = TestObjectWithBoolAndLen([])
|
||||
self.assert_results(call_bool_in_cond_no_breakgraph, obj)
|
||||
self.assert_results(call_bool_by_bool_no_breakgraph, obj)
|
||||
self.assert_results(call_bool_by_operator_truth_no_breakgraph, obj)
|
||||
|
||||
with test_instruction_translator_cache_context():
|
||||
layer = paddle.nn.Linear(10, 1)
|
||||
self.assert_results(call_bool_in_cond_no_breakgraph, layer)
|
||||
self.assert_results(call_bool_by_bool_no_breakgraph, layer)
|
||||
self.assert_results(
|
||||
call_bool_by_operator_truth_no_breakgraph, layer
|
||||
)
|
||||
|
||||
def test_object_allow_breakgraph(self):
|
||||
with test_instruction_translator_cache_context():
|
||||
obj = TestObjectWithLen([1, 2, 3])
|
||||
with strict_mode_guard(False):
|
||||
self.assert_results(call_bool_in_cond, obj)
|
||||
|
||||
self.assert_results(call_bool_by_bool, obj)
|
||||
self.assert_results(call_bool_by_operator_truth, obj)
|
||||
|
||||
with test_instruction_translator_cache_context():
|
||||
obj = TestObjectWithLen([])
|
||||
with strict_mode_guard(False):
|
||||
self.assert_results(call_bool_in_cond, obj)
|
||||
|
||||
self.assert_results(call_bool_by_bool, obj)
|
||||
self.assert_results(call_bool_by_operator_truth, obj)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,518 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import operator
|
||||
import unittest
|
||||
import weakref
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
def dispatch_len(x: paddle.Tensor):
|
||||
return len(x.shape)
|
||||
|
||||
|
||||
def dispatch_tensor_len(x: paddle.Tensor):
|
||||
return len(x)
|
||||
|
||||
|
||||
def dispatch_reversed(x: paddle.Tensor | int, y: paddle.Tensor | int):
|
||||
return list(reversed([x + 1, y - 1, x * 10, y + 1000]))
|
||||
|
||||
|
||||
def dispatch_bool(x: paddle.Tensor):
|
||||
return operator.truth(x.shape) and bool(x.shape)
|
||||
|
||||
|
||||
def dispatch_ceil(x: paddle.Tensor | float):
|
||||
return math.ceil(x) + 1
|
||||
|
||||
|
||||
def dispatch_floor(x: paddle.Tensor | float):
|
||||
return math.floor(x) + 1
|
||||
|
||||
|
||||
def test_sum_tuple(x: paddle.Tensor | int, y: paddle.Tensor | int):
|
||||
return sum((x, y))
|
||||
|
||||
|
||||
def test_sum_tuple2(
|
||||
x: paddle.Tensor | int | list[int] | list[paddle.Tensor],
|
||||
y: paddle.Tensor | int | list[int] | list[paddle.Tensor],
|
||||
):
|
||||
return sum((x, y), x)
|
||||
|
||||
|
||||
def test_sum_tuple3(x):
|
||||
return sum((), x)
|
||||
|
||||
|
||||
def test_sum_list(x: paddle.Tensor | int, y: paddle.Tensor | int):
|
||||
return sum([x, y])
|
||||
|
||||
|
||||
def test_sum_list2(
|
||||
x: paddle.Tensor | int | list[int] | list[paddle.Tensor],
|
||||
y: paddle.Tensor | int | list[int] | list[paddle.Tensor],
|
||||
):
|
||||
return sum([x, y], x)
|
||||
|
||||
|
||||
def test_sum_list3(x):
|
||||
return sum([], x)
|
||||
|
||||
|
||||
def test_tensor_sum(x: paddle.Tensor):
|
||||
return sum(x)
|
||||
|
||||
|
||||
def test_tensor_sum_api(x: paddle.Tensor):
|
||||
return x.sum()
|
||||
|
||||
|
||||
def test_pow(x: paddle.Tensor | int, y: paddle.Tensor | int):
|
||||
return pow(x, y)
|
||||
|
||||
|
||||
def test_pow2(x: paddle.Tensor | int, y: paddle.Tensor | int):
|
||||
return pow(x, y, 1)
|
||||
|
||||
|
||||
def test_tensor_pow_api(x: paddle.Tensor, y: paddle.Tensor | int):
|
||||
return x.pow(y)
|
||||
|
||||
|
||||
def test_math_pow(x: int, y: int):
|
||||
return math.pow(x, y)
|
||||
|
||||
|
||||
def test_chr(x: int | hex | paddle.Tensor):
|
||||
return chr(x)
|
||||
|
||||
|
||||
def test_ord(x: str):
|
||||
return ord(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_min():
|
||||
return min(9, 8, 2, 4, 1, 7, 3, 5, 6)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_max():
|
||||
return max(9, 8, 2, 4, 1, 7, 3, 5, 6)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_sqrt(x: int):
|
||||
return math.sqrt(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_log(x: int):
|
||||
return math.log(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_any(var):
|
||||
return any(var)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_any_iter(var):
|
||||
return any(iter(var))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_all(var):
|
||||
return all(var)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_all_iter(var):
|
||||
return all(iter(var))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_builtin_type_check_eq():
|
||||
a = 1
|
||||
b = []
|
||||
c = ()
|
||||
d = {}
|
||||
eq_results = (
|
||||
a == b, a == c, a == d,
|
||||
b == a, b == c, b == d,
|
||||
c == a, c == b, c == d,
|
||||
) # fmt: skip
|
||||
ne_results = (
|
||||
a != b, a != c, a != d,
|
||||
b != a, b != c, b != d,
|
||||
c != a, c != b, c != d,
|
||||
) # fmt: skip
|
||||
return eq_results, ne_results
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_is(x, y):
|
||||
return x is y
|
||||
|
||||
|
||||
class TestBuiltinDispatch(TestCaseBase):
|
||||
def test_dispatch_len(self):
|
||||
self.assert_results(dispatch_len, paddle.to_tensor([1, 2, 3]))
|
||||
|
||||
def test_dispatch_bool(self):
|
||||
self.assert_results(dispatch_bool, paddle.to_tensor([1, 2, 3]))
|
||||
|
||||
def test_dispatch_tensor_len(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(
|
||||
dispatch_tensor_len, paddle.to_tensor([1, 2, 3])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(
|
||||
dispatch_tensor_len, paddle.to_tensor([4, 5, 6])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
def test_dispatch_list_reversed(self):
|
||||
self.assert_results(dispatch_reversed, paddle.to_tensor(1), 2)
|
||||
self.assert_results(dispatch_reversed, 2, paddle.to_tensor(1))
|
||||
|
||||
def test_dispatch_tensor_reversed(self):
|
||||
self.assert_results(
|
||||
dispatch_reversed,
|
||||
paddle.to_tensor([1, 2]),
|
||||
paddle.to_tensor([3, 4]),
|
||||
)
|
||||
|
||||
def test_not_dispatch_tensor_ceil(self):
|
||||
# ceil should break graph, since it returns a int rather than a tensor
|
||||
self.assert_results(dispatch_ceil, paddle.to_tensor(1.2))
|
||||
|
||||
def test_dispatch_float_ceil(self):
|
||||
self.assert_results(dispatch_ceil, 1.2)
|
||||
|
||||
def test_not_dispatch_tensor_floor(self):
|
||||
# floor should break graph, since it returns a int rather than a tensor
|
||||
self.assert_results(dispatch_floor, paddle.to_tensor(1.2))
|
||||
|
||||
def test_dispatch_float_floor(self):
|
||||
self.assert_results(dispatch_floor, 1.2)
|
||||
|
||||
def test_dispatch_sum(self):
|
||||
self.assert_results(test_sum_tuple, 1, 1)
|
||||
self.assert_results(test_sum_tuple, paddle.to_tensor(1), 1)
|
||||
self.assert_results(
|
||||
test_sum_tuple, paddle.to_tensor(1), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_tuple, paddle.to_tensor([1, 2]), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_tuple, paddle.to_tensor([1, 2]), paddle.to_tensor([1, 3])
|
||||
)
|
||||
self.assert_results(test_sum_tuple2, 1, 1)
|
||||
self.assert_results(test_sum_tuple2, [1, 2], [3, 4])
|
||||
self.assert_results(test_sum_tuple2, paddle.to_tensor(1), 1)
|
||||
self.assert_results(
|
||||
test_sum_tuple2, paddle.to_tensor(1), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_tuple2,
|
||||
[paddle.to_tensor(1), paddle.to_tensor(2)],
|
||||
[paddle.to_tensor(3), paddle.to_tensor(4)],
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_tuple2, paddle.to_tensor([1, 2]), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_tuple2, paddle.to_tensor([1, 2]), paddle.to_tensor([1, 3])
|
||||
)
|
||||
self.assert_results(test_sum_tuple3, 1)
|
||||
self.assert_results(test_sum_tuple3, paddle.to_tensor(1))
|
||||
self.assert_results(test_sum_list, 1, 1)
|
||||
self.assert_results(test_sum_list, paddle.to_tensor(1), 1)
|
||||
self.assert_results(
|
||||
test_sum_list, paddle.to_tensor(1), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_list, paddle.to_tensor([1, 2]), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_list, paddle.to_tensor([1, 2]), paddle.to_tensor([1, 3])
|
||||
)
|
||||
self.assert_results(test_sum_list2, 1, 1)
|
||||
self.assert_results(test_sum_list2, [1, 2], [3, 4])
|
||||
self.assert_results(test_sum_list2, paddle.to_tensor(1), 1)
|
||||
self.assert_results(
|
||||
test_sum_list2, paddle.to_tensor(1), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_list2,
|
||||
[paddle.to_tensor(1), paddle.to_tensor(2)],
|
||||
[paddle.to_tensor(3), paddle.to_tensor(4)],
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_list2, paddle.to_tensor([1, 2]), paddle.to_tensor(1)
|
||||
)
|
||||
self.assert_results(
|
||||
test_sum_list2, paddle.to_tensor([1, 2]), paddle.to_tensor([1, 3])
|
||||
)
|
||||
self.assert_results(test_sum_list3, 1)
|
||||
self.assert_results(test_sum_list3, paddle.to_tensor(1))
|
||||
self.assert_results(test_tensor_sum, paddle.to_tensor([1, 2]))
|
||||
self.assert_results(test_tensor_sum, paddle.to_tensor((1, 2)))
|
||||
self.assert_results(test_tensor_sum_api, paddle.to_tensor([1, 2]))
|
||||
self.assert_results(test_tensor_sum_api, paddle.to_tensor((1, 2)))
|
||||
|
||||
def test_dispatch_pow(self):
|
||||
self.assert_results(test_pow, 2, 3)
|
||||
self.assert_results(test_pow, paddle.to_tensor(2), 3)
|
||||
self.assert_results(test_pow, paddle.to_tensor(2), paddle.to_tensor(3))
|
||||
self.assert_results(test_pow2, 2, 3)
|
||||
self.assert_results(test_math_pow, 2, 3)
|
||||
self.assert_results(test_tensor_pow_api, paddle.to_tensor(2), 3)
|
||||
self.assert_results(
|
||||
test_tensor_pow_api, paddle.to_tensor(2), paddle.to_tensor(3)
|
||||
)
|
||||
|
||||
def test_dispatch_chr(self):
|
||||
self.assert_results(test_chr, 65)
|
||||
self.assert_results(test_chr, 0x41)
|
||||
self.assert_results(test_chr, paddle.to_tensor(65))
|
||||
self.assert_results(test_chr, paddle.to_tensor(0x41))
|
||||
|
||||
def test_dispatch_ord(self):
|
||||
self.assert_results(test_ord, "a")
|
||||
|
||||
def test_dispatch_sqrt(self):
|
||||
self.assert_results(test_sqrt, 9)
|
||||
|
||||
def test_dispatch_log(self):
|
||||
self.assert_results(test_log, math.e)
|
||||
|
||||
def test_dispatch_min(self):
|
||||
self.assert_results(test_min)
|
||||
|
||||
def test_dispatch_max(self):
|
||||
self.assert_results(test_max)
|
||||
|
||||
def test_dispatch_builtin_type_check_eq(self):
|
||||
self.assert_results(test_builtin_type_check_eq)
|
||||
|
||||
def test_dispatch_any(self):
|
||||
l_pure_true = [1, True, 5, 6]
|
||||
l_pure_false = [False, 0, 0]
|
||||
l_true_and_false = [1, False, 0, 3]
|
||||
d_true = {"a": 1}
|
||||
d_false = {}
|
||||
self.assert_results(test_any, l_pure_true)
|
||||
self.assert_results(test_any, l_pure_false)
|
||||
self.assert_results(test_any, l_true_and_false)
|
||||
self.assert_results(test_any, d_true)
|
||||
self.assert_results(test_any, d_false)
|
||||
self.assert_results(test_any_iter, l_true_and_false)
|
||||
|
||||
def test_dispatch_all(self):
|
||||
l_pure_true = [1, True, 5, 6]
|
||||
l_pure_false = [False, 0, 0]
|
||||
l_true_and_false = [1, False, 0, 3]
|
||||
d_true = {"a": 1}
|
||||
d_false = {}
|
||||
self.assert_results(test_all, l_pure_true)
|
||||
self.assert_results(test_all, l_pure_false)
|
||||
self.assert_results(test_all, l_true_and_false)
|
||||
self.assert_results(test_all, d_true)
|
||||
self.assert_results(test_all, d_false)
|
||||
self.assert_results(test_all_iter, l_true_and_false)
|
||||
|
||||
def test_dispatch_is(self):
|
||||
x = paddle.ones(shape=[1, 2])
|
||||
y = paddle.ones(shape=[1, 2])
|
||||
# TODO(wangmingkai02): support comparison of same tensor object
|
||||
# self.assert_results(test_is, x, x)
|
||||
# self.assert_results(test_is, [x], [x])
|
||||
self.assert_results(test_is, x, y)
|
||||
self.assert_results(test_is, x, None)
|
||||
self.assert_results(test_is, [x], x)
|
||||
self.assert_results(test_is, None, x)
|
||||
self.assert_results(test_is, [x], None)
|
||||
self.assert_results(test_is, None, [x])
|
||||
self.assert_results(test_is, None, None)
|
||||
|
||||
|
||||
def run_getattr(x: paddle.Tensor):
|
||||
attr = 'dtype'
|
||||
out = getattr(x, attr)
|
||||
return out
|
||||
|
||||
|
||||
class TestGetattr(TestCaseBase):
|
||||
def test_getattr(self):
|
||||
x = paddle.to_tensor(4)
|
||||
self.assert_results(run_getattr, x)
|
||||
|
||||
|
||||
def tensor_hasattr(x: paddle.Tensor):
|
||||
return (
|
||||
hasattr(x, "dtype"),
|
||||
hasattr(x, "stop_gradient"),
|
||||
hasattr(x, "abs"),
|
||||
hasattr(x, "non_tensor_attr"),
|
||||
)
|
||||
|
||||
|
||||
class ObjectHasattr:
|
||||
def __init__(self):
|
||||
attr1 = 1
|
||||
attr2 = "2"
|
||||
attr3 = [3]
|
||||
|
||||
|
||||
def object_hasattr(x: ObjectHasattr):
|
||||
return (
|
||||
hasattr(x, "attr1"),
|
||||
hasattr(x, "attr2"),
|
||||
hasattr(x, "attr3"),
|
||||
hasattr(x, "non_obj_attr"),
|
||||
)
|
||||
|
||||
|
||||
def layer_hasattr(layer: paddle.nn.Layer):
|
||||
return (
|
||||
hasattr(layer, "parameters"),
|
||||
hasattr(layer, "sublayers"),
|
||||
hasattr(layer, "non_layer_attr"),
|
||||
)
|
||||
|
||||
|
||||
class TestHasattr(TestCaseBase):
|
||||
def test_tensor_hasattr(self):
|
||||
x = paddle.to_tensor(4)
|
||||
self.assert_results(tensor_hasattr, x)
|
||||
|
||||
def test_object_hasattr(self):
|
||||
x = ObjectHasattr()
|
||||
self.assert_results(object_hasattr, x)
|
||||
|
||||
def test_layer_hasattr(self):
|
||||
x = paddle.nn.Layer()
|
||||
self.assert_results(layer_hasattr, x)
|
||||
|
||||
|
||||
class WeakrefableObject: ...
|
||||
|
||||
|
||||
def weakref_breakgraph(obj):
|
||||
return weakref.ref(obj)
|
||||
|
||||
|
||||
class TestWeakref(TestCaseBase):
|
||||
def test_weakref_breakgraph(self):
|
||||
obj = WeakrefableObject()
|
||||
self.assert_results(weakref_breakgraph, obj)
|
||||
|
||||
|
||||
def test_builtin_type_conversion_breakgraph(x):
|
||||
return int(x), bool(x), float(x)
|
||||
|
||||
|
||||
class TestBuiltinTypeConversion(TestCaseBase):
|
||||
def test_builtin_type_conversion_breakgraph(self):
|
||||
self.assert_results(
|
||||
test_builtin_type_conversion_breakgraph, paddle.to_tensor(1.2)
|
||||
)
|
||||
self.assert_results(
|
||||
test_builtin_type_conversion_breakgraph, paddle.to_tensor(0)
|
||||
)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_native_code_function():
|
||||
res1 = paddle.base.libpaddle.is_compiled_with_avx()
|
||||
res2 = paddle.base.libpaddle.is_compiled_with_cuda()
|
||||
res3 = paddle.base.libpaddle.is_compiled_with_cudnn_frontend()
|
||||
res4 = paddle.base.libpaddle.is_compiled_with_rocm()
|
||||
res5 = paddle.base.libpaddle.is_compiled_with_custom_device("npu")
|
||||
res6 = paddle.base.libpaddle.is_compiled_with_ipu()
|
||||
res7 = paddle.base.libpaddle.is_compiled_with_xpu()
|
||||
res8_deprecated = (
|
||||
paddle.base.libpaddle.is_compiled_with_mkldnn()
|
||||
) # Paddle 3.3 deprecated
|
||||
res8 = paddle.base.libpaddle.is_compiled_with_onednn()
|
||||
res9 = paddle.base.libpaddle.is_compiled_with_nccl()
|
||||
res10 = paddle.base.libpaddle.is_compiled_with_mpi()
|
||||
res11 = paddle.base.libpaddle.is_compiled_with_mpi_aware()
|
||||
res12 = paddle.base.libpaddle.is_compiled_with_cinn()
|
||||
res13 = paddle.base.libpaddle.is_compiled_with_distribute()
|
||||
res14 = paddle.base.libpaddle.is_compiled_with_brpc()
|
||||
res15 = paddle.base.libpaddle.is_compiled_with_dist()
|
||||
|
||||
return (
|
||||
res1,
|
||||
res2,
|
||||
res3,
|
||||
res4,
|
||||
res5,
|
||||
res6,
|
||||
res7,
|
||||
res8_deprecated,
|
||||
res8,
|
||||
res9,
|
||||
res10,
|
||||
res11,
|
||||
res12,
|
||||
res13,
|
||||
res14,
|
||||
res15,
|
||||
)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_native_code_function_gpu_only():
|
||||
# Directly returning device_properties causes BreakGraph due to FallbackError:
|
||||
# "ObjectVariable does not implement '_reconstruct' method"
|
||||
# Therefore, we return individual properties as primitive types instead
|
||||
device_properties = paddle.device.cuda.get_device_properties()
|
||||
return (
|
||||
device_properties.name,
|
||||
device_properties.major,
|
||||
device_properties.minor,
|
||||
device_properties.total_memory,
|
||||
device_properties.multi_processor_count,
|
||||
)
|
||||
|
||||
|
||||
class TestNativeCodeFunction(TestCaseBase):
|
||||
def test_native_code_function(self):
|
||||
self.assert_results(test_native_code_function)
|
||||
|
||||
@unittest.skipUnless(paddle.device.is_compiled_with_cuda(), "requires CUDA")
|
||||
def test_native_code_function_gpu_only(self):
|
||||
self.assert_results(test_native_code_function_gpu_only)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,154 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
from paddle import Tensor, to_tensor
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
|
||||
|
||||
def double_num(num: float):
|
||||
return num * 2
|
||||
|
||||
|
||||
def double_num_with_breakgraph(num: float):
|
||||
sot.psdb.breakgraph()
|
||||
return num * 2
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_list(x: list):
|
||||
return list(map(double_num, x))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_list_comprehension(x: list):
|
||||
return [i for i in map(double_num, x)] # noqa: C416
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_tuple(x: tuple):
|
||||
return tuple(map(double_num, x))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_tuple_comprehension(x: tuple):
|
||||
return [i for i in map(double_num, x)] # noqa: C416
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_range(x: Iterable):
|
||||
return list(map(double_num, x))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_range_comprehension(x: Iterable):
|
||||
return [i for i in map(double_num, x)] # noqa: C416
|
||||
|
||||
|
||||
def add_dict_prefix(key: str):
|
||||
return f"dict_{key}"
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_dict(x: dict):
|
||||
return list(map(add_dict_prefix, x))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_dict_comprehension(x: dict):
|
||||
return [i for i in map(add_dict_prefix, x)] # noqa: C416
|
||||
|
||||
|
||||
def test_map_list_with_breakgraph(x: list):
|
||||
return list(map(double_num_with_breakgraph, x))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_unpack(x: list):
|
||||
a, b, c, d = map(double_num, x)
|
||||
return a, b, c, d
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_for_loop(x: list):
|
||||
res = 0
|
||||
for i in map(double_num, x):
|
||||
res += i
|
||||
return res
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_multi_input(func, a: Tensor, b: tuple[int, ...]):
|
||||
x, y, z = map(func, a, b)
|
||||
return x, y, z
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def test_map_with_zip_and_call_fn_ex(x: list[tuple[int, int]]):
|
||||
fn = lambda x: (0,) + x # noqa: RUF005
|
||||
map_results = map(fn, x)
|
||||
res = tuple(map(list, zip(*map_results)))
|
||||
return res
|
||||
|
||||
|
||||
class TestMap(TestCaseBase):
|
||||
def test_map(self):
|
||||
self.assert_results(test_map_list, [1, 2, 3, 4])
|
||||
self.assert_results(test_map_tuple, (1, 2, 3, 4))
|
||||
self.assert_results(test_map_range, range(5))
|
||||
self.assert_results(test_map_dict, {"a": 1, "b": 2, "c": 3})
|
||||
|
||||
def test_map_comprehension(self):
|
||||
self.assert_results(test_map_list_comprehension, [1, 2, 3, 4])
|
||||
self.assert_results(test_map_tuple_comprehension, (1, 2, 3, 4))
|
||||
self.assert_results(test_map_range_comprehension, range(5))
|
||||
self.assert_results(
|
||||
test_map_dict_comprehension, {"a": 1, "b": 2, "c": 3}
|
||||
)
|
||||
|
||||
def test_map_with_breakgraph(self):
|
||||
with strict_mode_guard(False):
|
||||
self.assert_results(test_map_list_with_breakgraph, [1, 2, 3, 4])
|
||||
|
||||
def test_map_unpack(self):
|
||||
self.assert_results(test_map_unpack, [1, 2, 3, 4])
|
||||
self.assert_results(
|
||||
test_map_multi_input,
|
||||
lambda x, y: x + y,
|
||||
to_tensor([1, 2, 3]),
|
||||
(2, 4, 6),
|
||||
)
|
||||
|
||||
def test_map_for_loop(self):
|
||||
self.assert_results(test_map_for_loop, [7, 8, 9, 10])
|
||||
|
||||
def test_map_with_zip_and_call_fn_ex(self):
|
||||
self.assert_results(
|
||||
test_map_with_zip_and_call_fn_ex, [(1, 2), (3, 4), (5, 6)]
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,92 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def test_range_1(stop: int):
|
||||
return range(stop)
|
||||
|
||||
|
||||
def test_range_2(start: int, stop: int):
|
||||
return range(start, stop)
|
||||
|
||||
|
||||
def test_range_3(start: int, stop: int, step: int):
|
||||
return range(start, stop, step)
|
||||
|
||||
|
||||
def test_range_4(stop: int, index: int):
|
||||
return range(stop)[index]
|
||||
|
||||
|
||||
def test_range_5(stop: int):
|
||||
return list(range(stop))
|
||||
|
||||
|
||||
def test_range_6(stop: int, index: int):
|
||||
return list(range(stop))[index]
|
||||
|
||||
|
||||
def test_range_7(index: int, tensor: paddle.Tensor):
|
||||
return list(range(len(tensor.shape)))[index]
|
||||
|
||||
|
||||
def test_range_8(stop: int):
|
||||
sum = 0
|
||||
for i in range(stop):
|
||||
sum += i
|
||||
return sum
|
||||
|
||||
|
||||
def test_range_9(stop: int, tensor: paddle.Tensor):
|
||||
for i in range(stop):
|
||||
tensor += i
|
||||
return tensor
|
||||
|
||||
|
||||
def test_range_10(stop: int, tensor: paddle.Tensor):
|
||||
for i in range(stop):
|
||||
for j in range(stop + 1):
|
||||
tensor += j
|
||||
return tensor
|
||||
|
||||
|
||||
class TestRange(TestCaseBase):
|
||||
def test_cases(self):
|
||||
start = 3
|
||||
stop = 10
|
||||
step = 2
|
||||
index = 1
|
||||
tensor = paddle.randn((10, 10))
|
||||
|
||||
self.assert_results(test_range_1, stop)
|
||||
self.assert_results(test_range_2, start, stop)
|
||||
self.assert_results(test_range_3, start, stop, step)
|
||||
self.assert_results(test_range_4, stop, index)
|
||||
self.assert_results(test_range_5, stop)
|
||||
self.assert_results(test_range_6, stop, index)
|
||||
self.assert_results(test_range_7, index, tensor)
|
||||
self.assert_results(test_range_8, stop)
|
||||
|
||||
self.assert_results(test_range_9, stop, paddle.randn((10,)))
|
||||
self.assert_results(test_range_10, stop, paddle.randn((10,)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,109 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import psdb, symbolic_translate
|
||||
from paddle.jit.sot.utils import min_graph_size_guard, strict_mode_guard
|
||||
|
||||
|
||||
def test_zip_1(x: int, y: int):
|
||||
for (id, val), val_ in zip(enumerate(range(x)), range(x)):
|
||||
if id % 2 == 0:
|
||||
y += val_
|
||||
return y
|
||||
|
||||
|
||||
def test_zip_2(x: list):
|
||||
return list(zip(x, range(len(x))))
|
||||
|
||||
|
||||
def test_zip_3(x: list):
|
||||
return tuple(zip(x, range(len(x))))
|
||||
|
||||
|
||||
def test_zip_4(x: paddle.Tensor):
|
||||
sum = 0
|
||||
for idx, val in zip(range(len(x)), x):
|
||||
sum += val
|
||||
return sum
|
||||
|
||||
|
||||
def test_zip_5(x: paddle.Tensor):
|
||||
sum = 0
|
||||
|
||||
for idx, val in zip(range(len(x)), x):
|
||||
for i in range(idx):
|
||||
sum += val
|
||||
return sum
|
||||
|
||||
|
||||
def test_zip_6(x: paddle.Tensor):
|
||||
sum = 0
|
||||
x = x.flatten()
|
||||
for idx, val in zip(range(len(x)), x):
|
||||
sum += val
|
||||
return sum
|
||||
|
||||
|
||||
def test_zip_7(layer_list, x):
|
||||
sum = 0
|
||||
for idx, layer in zip(range(len(layer_list)), layer_list):
|
||||
sum += layer(x)
|
||||
return sum
|
||||
|
||||
|
||||
def test_zip_8(iter_1, iter_2):
|
||||
sum = 0
|
||||
for a, b in zip(iter_1, iter_2):
|
||||
psdb.breakgraph()
|
||||
sum += a
|
||||
sum += b
|
||||
return sum
|
||||
|
||||
|
||||
class TestZip(TestCaseBase):
|
||||
def test_simple_cases(self):
|
||||
x = 8
|
||||
y = 5
|
||||
ty = paddle.randn((10, 10))
|
||||
layer_list = paddle.nn.LayerList(
|
||||
[paddle.nn.Linear(10, 10) for _ in range(3)]
|
||||
)
|
||||
self.assert_results(test_zip_1, x, y)
|
||||
self.assert_results(test_zip_2, [2, 4, 6, 8, 10])
|
||||
self.assert_results(test_zip_3, [2, 4, 6, 8, 10])
|
||||
self.assert_results(test_zip_4, ty)
|
||||
self.assert_results(test_zip_5, paddle.to_tensor([1, 2, 3]))
|
||||
self.assert_results(test_zip_6, ty)
|
||||
self.assert_results(test_zip_7, layer_list, paddle.randn((10,)))
|
||||
|
||||
@min_graph_size_guard(0)
|
||||
@strict_mode_guard(False)
|
||||
def test_reconstruct(self):
|
||||
self.assert_results(test_zip_8, [1, 2, 3], [4, 5, 6])
|
||||
|
||||
@strict_mode_guard(False)
|
||||
@min_graph_size_guard(0)
|
||||
def test_zip_user_defined_iter(self):
|
||||
sym_output = symbolic_translate(test_zip_8)(iter([1, 2, 3]), [4, 5, 6])
|
||||
paddle_output = test_zip_8(iter([1, 2, 3]), [4, 5, 6])
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,61 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.utils import try_ast_func, with_control_flow_guard
|
||||
|
||||
|
||||
@try_ast_func
|
||||
def calc(x, y, z):
|
||||
if x < 5:
|
||||
a = x + y
|
||||
b = y - z
|
||||
c = a * b
|
||||
return c
|
||||
else:
|
||||
a = x - y
|
||||
b = y + z
|
||||
c = a * b
|
||||
return c
|
||||
|
||||
|
||||
def inline_call_ast(x, y):
|
||||
a = x - y + 3
|
||||
b = x + y
|
||||
c = x * y
|
||||
z = calc(a, b, c)
|
||||
return z + a
|
||||
|
||||
|
||||
class TestNumPyAdd(TestCaseBase):
|
||||
@with_control_flow_guard(True)
|
||||
def test_full_graph_ast(self):
|
||||
x = paddle.to_tensor([2])
|
||||
y = paddle.to_tensor([3])
|
||||
z = paddle.to_tensor([4])
|
||||
self.assert_results(calc, x, y, z)
|
||||
|
||||
@with_control_flow_guard(True)
|
||||
def test_inline_ast(self):
|
||||
x = paddle.to_tensor([2])
|
||||
y = paddle.to_tensor([3])
|
||||
self.assert_results(inline_call_ast, x, y)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,83 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
patched = lambda self, x: x * self.a
|
||||
|
||||
patched2 = lambda self, x: x * self.a + 3
|
||||
|
||||
|
||||
class A:
|
||||
def __init__(self, a):
|
||||
self.a = a
|
||||
|
||||
def __call__(self, x):
|
||||
return self.add(x)
|
||||
|
||||
def add(self, x):
|
||||
return x + self.a
|
||||
|
||||
multi = patched
|
||||
|
||||
|
||||
class B:
|
||||
def __init__(self, a):
|
||||
self.a = A(a)
|
||||
|
||||
def __call__(self, x, func):
|
||||
return getattr(self.a, func)(x)
|
||||
|
||||
def self_call(self, x, func):
|
||||
return getattr(self.a, func)(self.a, x)
|
||||
|
||||
|
||||
def foo_1(a, x):
|
||||
return a(x)
|
||||
|
||||
|
||||
def foo_2(a, x):
|
||||
return a.multi(x)
|
||||
|
||||
|
||||
def foo_3(b, x):
|
||||
return b(x, "multi")
|
||||
|
||||
|
||||
def foo_4(b, x):
|
||||
return b(x, "add")
|
||||
|
||||
|
||||
def foo_5(b, x):
|
||||
return b.self_call(x, "multi")
|
||||
|
||||
|
||||
class TestCallObject(TestCaseBase):
|
||||
def test_simple(self):
|
||||
c = B(13)
|
||||
c.a.multi = patched2
|
||||
self.assert_results(foo_1, A(13), paddle.to_tensor(2))
|
||||
self.assert_results(foo_2, A(13), paddle.to_tensor(2))
|
||||
self.assert_results(foo_3, B(13), paddle.to_tensor(2))
|
||||
self.assert_results(foo_4, B(13), paddle.to_tensor(2))
|
||||
self.assert_results(foo_5, c, paddle.to_tensor(2))
|
||||
self.assert_results(foo_4, c, paddle.to_tensor(2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,106 @@
|
||||
# Copyright (c) 2025 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
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
|
||||
|
||||
@paddle.jit.marker.capture_control_flow
|
||||
def inner_fn_with_control_flow_explicit_capture(x):
|
||||
if x.sum() > 0:
|
||||
x += 1
|
||||
else:
|
||||
x -= 1
|
||||
return x
|
||||
|
||||
|
||||
def fn_with_control_flow_explicit_capture(x):
|
||||
x = inner_fn_with_control_flow_explicit_capture(x)
|
||||
return x + 1
|
||||
|
||||
|
||||
def fn_without_capture(x):
|
||||
if x.sum() > 0:
|
||||
x += 1
|
||||
else:
|
||||
x -= 1
|
||||
return x + 1
|
||||
|
||||
|
||||
class TestCaptureControlFlow(TestCaseBase):
|
||||
def test_case_without_capture_control_flow(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
x = paddle.full([3, 3], 1)
|
||||
self.assert_results(fn_without_capture, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
x = paddle.full([3, 3], -1)
|
||||
self.assert_results(fn_without_capture, x)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
|
||||
def test_case_capture_control_flow(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
x = paddle.full([3, 3], 1)
|
||||
self.assert_results(fn_with_control_flow_explicit_capture, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
x = paddle.full([3, 3], -1)
|
||||
self.assert_results(fn_with_control_flow_explicit_capture, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
|
||||
class NetWithCaptureControlFlow(nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.layer = nn.Linear(8, 8)
|
||||
|
||||
@paddle.jit.marker.capture_control_flow
|
||||
def fn(self, x):
|
||||
x = self.layer(x)
|
||||
if x.sum() > 0:
|
||||
x += paddle.ones_like(x)
|
||||
else:
|
||||
x -= paddle.zeros_like(x)
|
||||
return x
|
||||
|
||||
def forward(self, x):
|
||||
return self.fn(x) + 1
|
||||
|
||||
|
||||
def model_call(x: paddle.Tensor, net: paddle.nn.Layer):
|
||||
return net(x)
|
||||
|
||||
|
||||
class TestEagerParamsToPirValue(TestCaseBase):
|
||||
def test_case_without_capture_control_flow(self):
|
||||
model = NetWithCaptureControlFlow()
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
x = paddle.randn([4, 8])
|
||||
self.assert_results(model_call, x, model)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
x = paddle.randn([4, 8])
|
||||
self.assert_results(model_call, x, model)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,156 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import copy
|
||||
import types
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
from paddle.jit.sot.opcode_translator.executor.executor_cache import (
|
||||
OpcodeExecutorCache,
|
||||
)
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def test_instruction_translator_cache_context():
|
||||
cache = OpcodeExecutorCache()
|
||||
cache.clear()
|
||||
yield cache
|
||||
cache.clear()
|
||||
|
||||
|
||||
class TestCaseBase(unittest.TestCase):
|
||||
def assert_nest_match(self, actual, expected):
|
||||
cls_actual = type(actual)
|
||||
cls_expected = type(expected)
|
||||
msg = (
|
||||
f"type mismatch, actual is {cls_actual}, expected is {cls_expected}"
|
||||
)
|
||||
self.assertIs(cls_actual, cls_expected, msg=msg)
|
||||
|
||||
container_types = (tuple, list, dict, set)
|
||||
if cls_actual in container_types:
|
||||
msg = f"length mismatch, actual is {len(actual)}, expected is {len(expected)}"
|
||||
self.assertEqual(
|
||||
len(actual),
|
||||
len(expected),
|
||||
msg=msg,
|
||||
)
|
||||
if cls_actual in (tuple, list):
|
||||
for actual_item, expected_item in zip(actual, expected):
|
||||
self.assert_nest_match(actual_item, expected_item)
|
||||
elif cls_actual is dict:
|
||||
for actual_key, expected_key in zip(
|
||||
actual.keys(), expected.keys()
|
||||
):
|
||||
self.assert_nest_match(actual_key, expected_key)
|
||||
self.assert_nest_match(
|
||||
actual[actual_key], expected[expected_key]
|
||||
)
|
||||
elif cls_actual is set:
|
||||
# TODO: Nested set is not supported yet
|
||||
self.assertEqual(actual, expected)
|
||||
elif cls_actual in (np.ndarray, paddle.Tensor):
|
||||
# TODO: support assert_allclose github error log
|
||||
np.testing.assert_allclose(actual, expected, rtol=1e-6, atol=1e-8)
|
||||
else:
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def assert_results(self, func, *args, **kwargs):
|
||||
sym_output = symbolic_translate(func)(*args, **kwargs)
|
||||
paddle_output = func(*args, **kwargs)
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
def assert_results_with_grad(self, inputs, func, *args, **kwargs):
|
||||
def _find_all_tensors(obj):
|
||||
ret = []
|
||||
container_types = (tuple, list, set)
|
||||
if isinstance(obj, container_types):
|
||||
for item in obj:
|
||||
ret.extend(_find_all_tensors(item))
|
||||
elif isinstance(obj, dict):
|
||||
for value in obj.values():
|
||||
ret.extend(_find_all_tensors(value))
|
||||
elif isinstance(obj, paddle.Tensor):
|
||||
ret.append(obj)
|
||||
return ret
|
||||
|
||||
def _accumulate(tensors: list):
|
||||
out = paddle.empty(shape=[], dtype='float64')
|
||||
for tensor in tensors:
|
||||
out += paddle.mean(tensor.astype('float64'))
|
||||
return out
|
||||
|
||||
def _cal_input_grads(outputs):
|
||||
tensor_outs = _find_all_tensors(outputs)
|
||||
acc = _accumulate(tensor_outs)
|
||||
acc.backward()
|
||||
tensor_inputs = _find_all_tensors(inputs)
|
||||
input_grads = []
|
||||
for input in tensor_inputs:
|
||||
input_grads.append(
|
||||
None if input.grad is None else input.grad.clone()
|
||||
)
|
||||
input.clear_gradient()
|
||||
return input_grads
|
||||
|
||||
sym_output = symbolic_translate(func)(*args, **kwargs)
|
||||
paddle_output = func(*args, **kwargs)
|
||||
sym_input_grads = _cal_input_grads(sym_output)
|
||||
paddle_input_grads = _cal_input_grads(paddle_output)
|
||||
self.assert_nest_match(sym_input_grads, paddle_input_grads)
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
def assert_exceptions(self, exec, info, func, *args, **kwargs):
|
||||
self.assertRaisesRegex(
|
||||
exec, info, symbolic_translate(func), *args, **kwargs
|
||||
)
|
||||
|
||||
def assert_results_with_side_effects(self, func, *args, **kwargs):
|
||||
sym_args, sym_kwargs = copy.deepcopy((args, kwargs))
|
||||
sym_output = symbolic_translate(func)(*sym_args, **sym_kwargs)
|
||||
paddle_args, paddle_kwargs = copy.deepcopy((args, kwargs))
|
||||
paddle_output = func(*paddle_args, **paddle_kwargs)
|
||||
self.assert_nest_match(sym_args, paddle_args)
|
||||
self.assert_nest_match(sym_kwargs, paddle_kwargs)
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
def assert_results_with_global_check(
|
||||
self, func, global_keys: list[str], *args, **kwargs
|
||||
):
|
||||
def copy_fn(fn):
|
||||
return types.FunctionType(
|
||||
code=fn.__code__,
|
||||
globals=copy.copy(fn.__globals__),
|
||||
name=fn.__name__,
|
||||
argdefs=fn.__defaults__,
|
||||
closure=fn.__closure__,
|
||||
)
|
||||
|
||||
sym_copied_fn = copy_fn(func)
|
||||
sym_fn = symbolic_translate(sym_copied_fn)
|
||||
paddle_fn = copy_fn(func)
|
||||
sym_output = sym_fn(*args, **kwargs)
|
||||
paddle_output = paddle_fn(*args, **kwargs)
|
||||
for key in global_keys:
|
||||
self.assert_nest_match(
|
||||
sym_copied_fn.__globals__[key], paddle_fn.__globals__[key]
|
||||
)
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
@@ -0,0 +1,97 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from collections import namedtuple
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import psdb
|
||||
|
||||
Singleton = namedtuple("Singleton", ["a"])
|
||||
Pair = namedtuple("Pair", ["a", "b"])
|
||||
Triplet = namedtuple("Triple", ["a", "b", "c"])
|
||||
Quartet = namedtuple("Quartet", ["a", "b", "c", "d"])
|
||||
QuartetWithDefault = namedtuple(
|
||||
"QuartetWithDefault", ["a", "b", "c", "d"], defaults=[1, 2, 3]
|
||||
)
|
||||
|
||||
|
||||
@psdb.check_no_breakgraph
|
||||
def create_namedtuple():
|
||||
x = Singleton(1)
|
||||
y = Singleton(2)
|
||||
z = Singleton(3)
|
||||
return x.a + y.a + z.a
|
||||
|
||||
|
||||
@psdb.check_no_breakgraph
|
||||
def create_namedtuple_with_tensor(x):
|
||||
y = Pair(x + 1, x + 2)
|
||||
z = Pair(x + 3, x + 4)
|
||||
return y.a + y.b + z.a + z.b
|
||||
|
||||
|
||||
@psdb.check_no_breakgraph
|
||||
def load_namedtuple(x, y):
|
||||
return x.a + y.a + y.b
|
||||
|
||||
|
||||
@psdb.check_no_breakgraph
|
||||
def create_namedtuple_with_default():
|
||||
u = QuartetWithDefault(1, 2, 3, 4)
|
||||
v = QuartetWithDefault(5, 6, 7)
|
||||
w = QuartetWithDefault(8, 9)
|
||||
x = QuartetWithDefault(10)
|
||||
return (
|
||||
(u.a + u.b + u.c + u.d)
|
||||
+ (v.a + v.b + v.c + v.d)
|
||||
+ (w.a + w.b + w.c + w.d)
|
||||
+ (x.a + x.b + x.c + x.d)
|
||||
)
|
||||
|
||||
|
||||
@psdb.check_no_breakgraph
|
||||
def get_fields():
|
||||
x = Singleton(1)
|
||||
y = Pair(2, 3)
|
||||
z = Triplet(4, 5, 6)
|
||||
return x._fields + y._fields + z._fields
|
||||
|
||||
|
||||
class TestNamedTuple(TestCaseBase):
|
||||
def test_create_namedtuple(self):
|
||||
self.assert_results(create_namedtuple)
|
||||
|
||||
def test_create_namedtuple_with_tensor(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(create_namedtuple_with_tensor, x)
|
||||
|
||||
def test_load_namedtuple(self):
|
||||
x = Singleton(paddle.to_tensor(1))
|
||||
y = Pair(paddle.to_tensor(2), paddle.to_tensor(3))
|
||||
self.assert_results(load_namedtuple, x, y)
|
||||
|
||||
def test_create_namedtuple_with_default(self):
|
||||
self.assert_results(create_namedtuple_with_default)
|
||||
|
||||
def test_get_fields(self):
|
||||
self.assert_results(get_fields)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,54 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# New Supported Instructions:
|
||||
# BUILD_MAP (new)
|
||||
# BUILD_CONST_KEY_MAP (new)
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def func_1(format_str, tensor):
|
||||
str = format_str.format(xx=12)
|
||||
a = "{xx} = 12".format
|
||||
ttt = f"{10} = 12"
|
||||
a(xx=12)
|
||||
tensor = tensor + 1
|
||||
return str, tensor
|
||||
|
||||
|
||||
def func_2(format_str, tensor):
|
||||
str = format_str % 10
|
||||
tensor = tensor + 1
|
||||
return str, tensor
|
||||
|
||||
|
||||
class TestConstantGraph(TestCaseBase):
|
||||
def test_case_1(self):
|
||||
x = "{xx} is xx"
|
||||
tensor = paddle.to_tensor(1)
|
||||
self.assert_results(func_1, x, tensor)
|
||||
|
||||
def test_case_2(self):
|
||||
x = "%s is xx"
|
||||
tensor = paddle.to_tensor(1)
|
||||
self.assert_results(func_2, x, tensor)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,197 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataTensor:
|
||||
x: paddle.Tensor
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataInt:
|
||||
x: int
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataTensorWithPostInit:
|
||||
x: paddle.Tensor
|
||||
|
||||
def __post_init__(self):
|
||||
self.x += 1
|
||||
|
||||
|
||||
@dataclass
|
||||
class MultiInheritDataTensor(DataTensorWithPostInit):
|
||||
place: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class MultiInheritDataTensorWithIdx(MultiInheritDataTensor):
|
||||
idx: int
|
||||
|
||||
|
||||
def return_dataclass(x):
|
||||
return DataTensor(x + 1)
|
||||
|
||||
|
||||
def return_dataclass_with_post_init(x):
|
||||
return DataTensorWithPostInit(x)
|
||||
|
||||
|
||||
def return_dataclass_with_multi_inherit(x, place="gpu", idx=-1):
|
||||
return MultiInheritDataTensorWithIdx(x, place, idx)
|
||||
|
||||
|
||||
class TestDataclassBasic(TestCaseBase):
|
||||
def test_dtype_reconstruct(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(return_dataclass, x)
|
||||
|
||||
def test_dtype_reconstruct_with_post_init(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(return_dataclass_with_post_init, x)
|
||||
|
||||
def test_dtype_reconstruct_with_multi_inherit(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(return_dataclass_with_multi_inherit, x, "nyapu", 1)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DataMeta:
|
||||
x: paddle.Tensor
|
||||
y: paddle.Tensor | None = None
|
||||
m: list[list[paddle.Tensor]] = field(default_factory=list)
|
||||
n: int = 0
|
||||
|
||||
def __post_init__(self):
|
||||
self.x += 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def is_data_int_eq(data1: DataInt, data2: DataInt):
|
||||
return data1 == data2
|
||||
|
||||
|
||||
def is_data_tensor_eq(data1: DataTensor, data2: DataTensor):
|
||||
return data1 == data2
|
||||
|
||||
|
||||
def is_any_eq(data1, data2):
|
||||
return data1 == data2
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def get_attr(data: DataMeta):
|
||||
return data.x + data.y
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def set_attr(data: DataMeta):
|
||||
ori_x = data.x
|
||||
data.x = data.x + data.n
|
||||
res = data.x
|
||||
data.x = ori_x
|
||||
return res
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def get__dataclass_fields__(data: DataMeta):
|
||||
return list(data.__dataclass_fields__), list(
|
||||
data.__class__.__dataclass_fields__
|
||||
)
|
||||
|
||||
|
||||
class TestDataClassInstance(TestCaseBase):
|
||||
def test_get_attr(self):
|
||||
dm = DataMeta(x=paddle.randn([1, 2]), y=paddle.randn([1]))
|
||||
self.assert_results(get_attr, dm)
|
||||
self.assert_results(get__dataclass_fields__, dm)
|
||||
|
||||
def test_set_attr(self):
|
||||
dm = DataMeta(x=paddle.ones([1, 2]), n=2)
|
||||
self.assert_results(set_attr, dm)
|
||||
|
||||
def test_eq_int(self):
|
||||
di1 = DataInt(x=1)
|
||||
di2 = DataInt(x=1)
|
||||
di3 = DataInt(x=2)
|
||||
self.assert_results(is_data_int_eq, di1, di2)
|
||||
self.assert_results(is_data_int_eq, di1, di3)
|
||||
|
||||
def test_eq_tensor(self):
|
||||
t = paddle.randn([1])
|
||||
dt1 = DataTensor(x=t)
|
||||
dt2 = DataTensor(x=t)
|
||||
dt3 = DataTensor(x=paddle.zeros([1]))
|
||||
self.assert_results(is_data_tensor_eq, dt1, dt2)
|
||||
self.assert_results(is_data_tensor_eq, dt1, dt3)
|
||||
|
||||
def test_eq_diff_dataclass(self):
|
||||
di = DataInt(x=1)
|
||||
dt = DataTensor(x=1) # type: ignore
|
||||
self.assert_results(is_data_int_eq, di, dt)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ComplexDataClass:
|
||||
a: int
|
||||
b: int = 0
|
||||
c: int = field(default=1)
|
||||
d: int = field(default_factory=lambda: 2, kw_only=True)
|
||||
|
||||
|
||||
def create_dataclass_with_a():
|
||||
return ComplexDataClass(0)
|
||||
|
||||
|
||||
def create_dataclass_with_kwarg_a():
|
||||
return ComplexDataClass(a=1)
|
||||
|
||||
|
||||
def create_dataclass_with_a_b_c():
|
||||
return ComplexDataClass(1, 2, 3)
|
||||
|
||||
|
||||
def create_dataclass_with_kwarg_a_b_c():
|
||||
return ComplexDataClass(1, 2, 3)
|
||||
|
||||
|
||||
class TestDataClassConstruction(TestCaseBase):
|
||||
def test_create_dataclass_with_a(self):
|
||||
self.assert_results(create_dataclass_with_a)
|
||||
|
||||
def test_create_dataclass_with_kwarg_a(self):
|
||||
self.assert_results(create_dataclass_with_kwarg_a)
|
||||
|
||||
def test_create_dataclass_with_a_b_c(self):
|
||||
self.assert_results(create_dataclass_with_a_b_c)
|
||||
|
||||
def test_create_dataclass_with_kwarg_a_b_c(self):
|
||||
self.assert_results(create_dataclass_with_kwarg_a_b_c)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,61 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import breakgraph
|
||||
|
||||
|
||||
def test_delete_fast(a):
|
||||
a = a + 2
|
||||
t = a * 3
|
||||
del t
|
||||
return a
|
||||
|
||||
|
||||
def inner_call_with_breakgraph(a):
|
||||
breakgraph()
|
||||
return a + 1
|
||||
|
||||
|
||||
def test_delete_fast_with_breakgraph(a):
|
||||
a = a + 2
|
||||
t1 = a * 3
|
||||
out1 = inner_call_with_breakgraph(a + t1)
|
||||
t2 = a - 4
|
||||
t3 = a / 5
|
||||
out2 = inner_call_with_breakgraph(t1 + t2)
|
||||
del t1, t2, t3
|
||||
return a + out1 + out2
|
||||
|
||||
|
||||
class TestDeleteFast(TestCaseBase):
|
||||
def test_simple(self):
|
||||
a = paddle.to_tensor(1)
|
||||
self.assert_results(test_delete_fast, a)
|
||||
|
||||
|
||||
class TestDeleteFastWithBreakGraph(TestCaseBase):
|
||||
def test_delete_fast_with_break_graph(self):
|
||||
a = paddle.to_tensor(1)
|
||||
self.assert_results(test_delete_fast_with_breakgraph, a)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,82 @@
|
||||
# Copyright (c) 2024 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
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def tensor_astype(x, y):
|
||||
z = x.astype(y.dtype)
|
||||
return z
|
||||
|
||||
|
||||
def tensor_dtype_guard(x):
|
||||
return x + 1
|
||||
|
||||
|
||||
def reconstruct_dtype():
|
||||
x = paddle.to_tensor(1)
|
||||
z = x.dtype
|
||||
if x > 0:
|
||||
y = paddle.to_tensor(1, dtype=z)
|
||||
else:
|
||||
y = 1
|
||||
return y
|
||||
|
||||
|
||||
def dtype_guard(x, cast_map):
|
||||
out = paddle.cast(x, cast_map[x.dtype])
|
||||
return out, out.dtype
|
||||
|
||||
|
||||
class TestTensorAstype(TestCaseBase):
|
||||
def test_tensor_astype(self):
|
||||
x = paddle.ones([2, 3], dtype="float32")
|
||||
y = paddle.ones([2, 3], dtype="int32")
|
||||
self.assert_results(tensor_astype, x, y)
|
||||
|
||||
|
||||
class TestTensorDtypeGuard(TestCaseBase):
|
||||
def test_tensor_dtype_guard(self):
|
||||
x = paddle.ones([2, 3], dtype="float32")
|
||||
y = paddle.ones([2, 3], dtype="int32")
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(tensor_dtype_guard, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(tensor_dtype_guard, y)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(tensor_dtype_guard, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
class TestDtypeReconstruct(TestCaseBase):
|
||||
def test_dtype_reconstruct(self):
|
||||
self.assert_results(reconstruct_dtype)
|
||||
|
||||
|
||||
class TestDtypeGuard(TestCaseBase):
|
||||
def test_dtype_guard(self):
|
||||
dtype_map = {paddle.float32: paddle.float64}
|
||||
x = paddle.ones([2, 3], dtype="float32")
|
||||
self.assert_results(dtype_guard, x, dtype_map)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,49 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def func_dup_top_1():
|
||||
return True == True != False
|
||||
|
||||
|
||||
def func_dup_top_2(x):
|
||||
y = x + 1
|
||||
return True == True != False
|
||||
|
||||
|
||||
def func_dup_top_two(x: list[paddle.Tensor]):
|
||||
x[0] += x[1]
|
||||
return x
|
||||
|
||||
|
||||
class TestDupTop(TestCaseBase):
|
||||
def test_dup_top(self):
|
||||
self.assert_results(func_dup_top_1)
|
||||
self.assert_results(func_dup_top_2, paddle.to_tensor(1.0))
|
||||
# TODO: fix this after we support side effect
|
||||
# self.assert_results(
|
||||
# func_dup_top_two, [paddle.to_tensor(1.0), paddle.to_tensor(2.0)]
|
||||
# )
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,118 @@
|
||||
# Copyright (c) 2025 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
|
||||
from enum import IntEnum
|
||||
from typing import Any
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
class Direction(IntEnum):
|
||||
UP = 1
|
||||
RIGHT = 2
|
||||
DOWN = 3
|
||||
LEFT = 4
|
||||
|
||||
|
||||
class Direction2(IntEnum):
|
||||
EAST = 1
|
||||
WEST = 2
|
||||
NORTH = 3
|
||||
SOUTH = 4
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def eq_func(x: IntEnum, y: IntEnum):
|
||||
return x == y
|
||||
|
||||
|
||||
def eq_func_2(x: IntEnum, y: Any):
|
||||
return x == y
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def not_eq_func(x: IntEnum, y: IntEnum):
|
||||
return x != y
|
||||
|
||||
|
||||
def not_eq_func_2(x: IntEnum, y: Any):
|
||||
return x != y
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def name_func(x: IntEnum):
|
||||
return x.name
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def is_func(x: IntEnum, y: IntEnum):
|
||||
return x is y
|
||||
|
||||
|
||||
def get_func(x: int):
|
||||
return Direction(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def get_func_2(x: str):
|
||||
return Direction[x]
|
||||
|
||||
|
||||
class TestEnumMethod(TestCaseBase):
|
||||
def test_guard(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(eq_func, Direction.UP, Direction.UP)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(eq_func, Direction.UP, Direction.DOWN)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(eq_func, Direction.UP, Direction.UP)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(eq_func, Direction.UP, Direction2.EAST)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
|
||||
def test_eq(self):
|
||||
self.assert_results(eq_func, Direction.UP, Direction.UP)
|
||||
self.assert_results(eq_func, Direction.RIGHT, Direction.LEFT)
|
||||
self.assert_results(eq_func, Direction.UP, Direction2.EAST)
|
||||
self.assert_results(eq_func_2, Direction.UP, 1)
|
||||
|
||||
def test_not_eq(self):
|
||||
self.assert_results(not_eq_func, Direction.UP, Direction.UP)
|
||||
self.assert_results(not_eq_func, Direction.UP, Direction.DOWN)
|
||||
self.assert_results(not_eq_func, Direction.UP, Direction2.EAST)
|
||||
self.assert_results(not_eq_func_2, Direction.UP, 0)
|
||||
|
||||
def test_name(self):
|
||||
self.assert_results(name_func, Direction.UP)
|
||||
|
||||
def test_is(self):
|
||||
self.assert_results(is_func, Direction.UP, Direction.UP)
|
||||
self.assert_results(is_func, Direction.RIGHT, Direction.LEFT)
|
||||
self.assert_results(is_func, Direction.UP, Direction2.EAST)
|
||||
|
||||
def test_get(self):
|
||||
# TODO(wangmingkai): implement “_reconstruct” for EnumVariable
|
||||
# self.assert_results(get_func, 1)
|
||||
self.assert_results(get_func_2, 'UP')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,117 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
def test_enumerate_1(x: int, y: int):
|
||||
for id, val in enumerate(range(x)):
|
||||
if id % 2 == 0:
|
||||
y += val
|
||||
return y
|
||||
|
||||
|
||||
def test_enumerate_2(x: list):
|
||||
return list(enumerate(x))
|
||||
|
||||
|
||||
def test_enumerate_3(x: list):
|
||||
return tuple(enumerate(x))
|
||||
|
||||
|
||||
def test_enumerate_4(x: paddle.Tensor):
|
||||
sum = 0
|
||||
for idx, val in enumerate(x):
|
||||
sum += val
|
||||
return sum
|
||||
|
||||
|
||||
# TODO(zmh): support range for tensor
|
||||
def test_enumerate_5(x: paddle.Tensor):
|
||||
sum = 0
|
||||
|
||||
for idx, val in enumerate(x):
|
||||
for i in range(val):
|
||||
sum += val
|
||||
return sum
|
||||
|
||||
|
||||
def test_enumerate_6(x: paddle.Tensor):
|
||||
sum = 0
|
||||
|
||||
for idx, val in enumerate(x):
|
||||
for i in range(idx):
|
||||
sum += val
|
||||
return sum
|
||||
|
||||
|
||||
def test_enumerate_7(x: paddle.Tensor):
|
||||
sum = 0
|
||||
x = x.flatten()
|
||||
for idx, val in enumerate(x):
|
||||
sum += val
|
||||
return sum
|
||||
|
||||
|
||||
# TODO(zmh): support -1
|
||||
def test_enumerate_8(x: paddle.Tensor):
|
||||
sum = 0
|
||||
x = paddle.nonzero(x, as_tuple=False)
|
||||
for idx, val in enumerate(x):
|
||||
sum += val
|
||||
return sum
|
||||
|
||||
|
||||
def test_enumerate_10(layer_list, x):
|
||||
sum = 0
|
||||
for idx, layer in enumerate(layer_list):
|
||||
sum += layer(x)
|
||||
return sum
|
||||
|
||||
|
||||
class TestEnumerate(TestCaseBase):
|
||||
def test_cases(self):
|
||||
x = 8
|
||||
y = 5
|
||||
ty = paddle.randn((10, 10))
|
||||
layer_list = paddle.nn.LayerList(
|
||||
[paddle.nn.Linear(10, 10) for _ in range(3)]
|
||||
)
|
||||
|
||||
self.assert_results(test_enumerate_1, x, y)
|
||||
self.assert_results(test_enumerate_2, [2, 4, 6, 8, 10])
|
||||
self.assert_results(test_enumerate_3, [2, 4, 6, 8, 10])
|
||||
|
||||
self.assert_results(test_enumerate_4, ty)
|
||||
# TODO(zmh): support range for tensor
|
||||
|
||||
with strict_mode_guard(False):
|
||||
self.assert_results(test_enumerate_5, paddle.to_tensor([1, 2, 3]))
|
||||
self.assert_results(test_enumerate_6, paddle.to_tensor([1, 2, 3]))
|
||||
self.assert_results(test_enumerate_7, ty)
|
||||
# TODO(zmh): support -1
|
||||
|
||||
with strict_mode_guard(False):
|
||||
self.assert_results(test_enumerate_8, ty)
|
||||
|
||||
self.assert_results(test_enumerate_10, layer_list, paddle.randn((10,)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,258 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from paddle.jit.sot.utils import PEP508LikeEnvironmentVariable
|
||||
from paddle.utils.environments import (
|
||||
BooleanEnvironmentVariable,
|
||||
EnvironmentVariableGuard,
|
||||
IntegerEnvironmentVariable,
|
||||
StringEnvironmentVariable,
|
||||
)
|
||||
|
||||
|
||||
class TestBooleanEnvironmentVariable(unittest.TestCase):
|
||||
def test_bool_env_get(self):
|
||||
env_name = "___TEST_ENV_BOOL_GET"
|
||||
env_bool = BooleanEnvironmentVariable(env_name, False)
|
||||
|
||||
self.assertIs(env_bool.get(), False)
|
||||
|
||||
os.environ[env_name] = "False"
|
||||
self.assertIs(env_bool.get(), False)
|
||||
|
||||
os.environ[env_name] = "OFF"
|
||||
self.assertIs(env_bool.get(), False)
|
||||
|
||||
os.environ[env_name] = "0"
|
||||
self.assertIs(env_bool.get(), False)
|
||||
|
||||
os.environ[env_name] = "True"
|
||||
self.assertIs(env_bool.get(), True)
|
||||
|
||||
os.environ[env_name] = "ON"
|
||||
self.assertIs(env_bool.get(), True)
|
||||
|
||||
os.environ[env_name] = "1"
|
||||
self.assertIs(env_bool.get(), True)
|
||||
|
||||
def test_bool_env_set(self):
|
||||
env_name = "___TEST_ENV_BOOL_SET"
|
||||
env_bool = BooleanEnvironmentVariable(env_name, False)
|
||||
|
||||
env_bool.set(True)
|
||||
self.assertIs(env_bool.get(), True)
|
||||
|
||||
env_bool.set(False)
|
||||
self.assertIs(env_bool.get(), False)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_bool.set("True")
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_bool.set("False")
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_bool.set(0)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_bool.set(1)
|
||||
|
||||
def test_bool_env_guard(self):
|
||||
env_name = "___TEST_ENV_BOOL_GUARD"
|
||||
env_bool = BooleanEnvironmentVariable(env_name, False)
|
||||
|
||||
with EnvironmentVariableGuard(env_bool, True):
|
||||
self.assertIs(env_bool.get(), True)
|
||||
|
||||
with EnvironmentVariableGuard(env_bool, False):
|
||||
self.assertIs(env_bool.get(), False)
|
||||
|
||||
|
||||
class TestStringEnvironmentVariable(unittest.TestCase):
|
||||
def test_str_env_get(self):
|
||||
env_name = "___TEST_ENV_STR_GET"
|
||||
env_str = StringEnvironmentVariable(env_name, "DEFAULT")
|
||||
|
||||
self.assertEqual(env_str.get(), "DEFAULT")
|
||||
|
||||
os.environ[env_name] = "CASE1"
|
||||
self.assertEqual(env_str.get(), "CASE1")
|
||||
|
||||
os.environ[env_name] = "CASE2"
|
||||
self.assertEqual(env_str.get(), "CASE2")
|
||||
|
||||
def test_str_env_set(self):
|
||||
env_name = "___TEST_ENV_STR_SET"
|
||||
env_str = StringEnvironmentVariable(env_name, "DEFAULT")
|
||||
|
||||
self.assertEqual(env_str.get(), "DEFAULT")
|
||||
|
||||
env_str.set("CASE1")
|
||||
self.assertEqual(env_str.get(), "CASE1")
|
||||
|
||||
env_str.set("CASE2")
|
||||
self.assertEqual(env_str.get(), "CASE2")
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_str.set(True)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_str.set(False)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_str.set(0)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_str.set(1)
|
||||
|
||||
def test_str_env_guard(self):
|
||||
env_name = "___TEST_ENV_STR_GUARD"
|
||||
env_str = StringEnvironmentVariable(env_name, "DEFAULT")
|
||||
|
||||
with EnvironmentVariableGuard(env_str, "CASE1"):
|
||||
self.assertEqual(env_str.get(), "CASE1")
|
||||
|
||||
with EnvironmentVariableGuard(env_str, "CASE2"):
|
||||
self.assertEqual(env_str.get(), "CASE2")
|
||||
|
||||
|
||||
class TestIntegerEnvironmentVariable(unittest.TestCase):
|
||||
def test_int_env_get(self):
|
||||
env_name = "___TEST_ENV_INT_GET"
|
||||
env_int = IntegerEnvironmentVariable(env_name, 42)
|
||||
|
||||
self.assertEqual(env_int.get(), 42)
|
||||
|
||||
os.environ[env_name] = "10"
|
||||
self.assertEqual(env_int.get(), 10)
|
||||
|
||||
os.environ[env_name] = "99999"
|
||||
self.assertEqual(env_int.get(), 99999)
|
||||
|
||||
def test_int_env_set(self):
|
||||
env_name = "___TEST_ENV_INT_SET"
|
||||
env_int = IntegerEnvironmentVariable(env_name, 42)
|
||||
|
||||
self.assertEqual(env_int.get(), 42)
|
||||
|
||||
env_int.set(99)
|
||||
self.assertEqual(env_int.get(), 99)
|
||||
|
||||
env_int.set(1000)
|
||||
self.assertEqual(env_int.get(), 1000)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_int.set(True)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_int.set(False)
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_int.set("10")
|
||||
|
||||
with self.assertRaises(AssertionError):
|
||||
env_int.set("42")
|
||||
|
||||
def test_int_env_guard(self):
|
||||
env_name = "___TEST_ENV_INT_GUARD"
|
||||
env_int = IntegerEnvironmentVariable(env_name, 42)
|
||||
|
||||
with EnvironmentVariableGuard(env_int, 99):
|
||||
self.assertEqual(env_int.get(), 99)
|
||||
|
||||
with EnvironmentVariableGuard(env_int, 1000):
|
||||
self.assertEqual(env_int.get(), 1000)
|
||||
|
||||
|
||||
class TestPEP508LikeEnvironmentVariable(unittest.TestCase):
|
||||
def test_PEP508_like_env_get(self):
|
||||
env_name = "___TEST_ENV_PEP508LikeDict_GET"
|
||||
env_PEP508_like = PEP508LikeEnvironmentVariable(env_name, {})
|
||||
|
||||
if env_name in os.environ:
|
||||
del os.environ[env_name]
|
||||
|
||||
self.assertEqual(env_PEP508_like.get(), {})
|
||||
|
||||
os.environ[env_name] = "subgraph_info"
|
||||
self.assertEqual(env_PEP508_like.get(), {"subgraph_info": []})
|
||||
|
||||
os.environ[env_name] = ""
|
||||
self.assertEqual(env_PEP508_like.get(), {})
|
||||
|
||||
os.environ[env_name] = "subgraph_info[ops, data, relationships]"
|
||||
self.assertEqual(
|
||||
env_PEP508_like.get(),
|
||||
{"subgraph_info": ["ops", "data", "relationships"]},
|
||||
)
|
||||
|
||||
os.environ[env_name] = (
|
||||
"subgraph_info[ops, data, relationships], breakgraph_reason[inlinecall, others]"
|
||||
)
|
||||
self.assertEqual(
|
||||
env_PEP508_like.get(),
|
||||
{
|
||||
"subgraph_info": ["ops", "data", "relationships"],
|
||||
"breakgraph_reason": ["inlinecall", "others"],
|
||||
},
|
||||
)
|
||||
|
||||
os.environ[env_name] = "subgraph_info[ops, [[[[[[[[]], relationships], "
|
||||
self.assertEqual(
|
||||
env_PEP508_like.get(),
|
||||
{
|
||||
"subgraph_info": ["ops", "[[[[[[[[]]", "relationships"],
|
||||
},
|
||||
)
|
||||
|
||||
os.environ[env_name] = "subgraph_info[ops, , , relationships], "
|
||||
self.assertEqual(
|
||||
env_PEP508_like.get(),
|
||||
{
|
||||
"subgraph_info": ["ops", "relationships"],
|
||||
},
|
||||
)
|
||||
|
||||
def test_PEP508_like_env_set(self):
|
||||
env_name = "___TEST_ENV_PEP508LikeDict_GET"
|
||||
env_PEP508_like = PEP508LikeEnvironmentVariable(env_name, {})
|
||||
|
||||
env_PEP508_like.set(
|
||||
{
|
||||
"subgraph_info": ["ops", "data", "relationships"],
|
||||
"breakgraph_reason": ["inlinecall", "others"],
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
os.environ[env_name],
|
||||
"subgraph_info[ops,data,relationships],breakgraph_reason[inlinecall,others]",
|
||||
)
|
||||
|
||||
env_PEP508_like.set({"subgraph_info": []})
|
||||
self.assertEqual(os.environ[env_name], "subgraph_info")
|
||||
|
||||
env_PEP508_like.set({})
|
||||
self.assertEqual(
|
||||
os.environ[env_name],
|
||||
"",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,40 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
def fn_with_try_except():
|
||||
sot.psdb.breakgraph()
|
||||
sot.psdb.fallback()
|
||||
try:
|
||||
raise ValueError("ValueError")
|
||||
except ValueError:
|
||||
print("catch ValueError")
|
||||
return True
|
||||
|
||||
|
||||
class TestErrorHandling(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_fn_with_try_except(self):
|
||||
self.assert_results(fn_with_try_except)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,65 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
from paddle.static import BuildStrategy
|
||||
|
||||
|
||||
def func(x, y):
|
||||
ret = 2 * x
|
||||
ret = paddle.nn.functional.relu(ret)
|
||||
ret = ret + y
|
||||
return ret
|
||||
|
||||
|
||||
def simple(x):
|
||||
ret = 2 * x
|
||||
return ret
|
||||
|
||||
|
||||
class TestExecutionBase(TestCaseBase):
|
||||
def test_simple(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
y = paddle.to_tensor([2.0])
|
||||
self.assert_results(simple, x)
|
||||
self.assert_results(simple, y)
|
||||
|
||||
|
||||
def foo(x):
|
||||
out = x + 1
|
||||
out = out * 2
|
||||
out = paddle.nn.functional.relu(out)
|
||||
return out
|
||||
|
||||
|
||||
class TestBackend(TestCaseBase):
|
||||
def test_backend(self):
|
||||
x = paddle.randn([2, 3])
|
||||
dy_out = foo(x)
|
||||
# TODO(SigureMo): Find a better way to test the CINN backend.
|
||||
if not paddle.is_compiled_with_cinn():
|
||||
return
|
||||
sot_out = symbolic_translate(
|
||||
foo, build_strategy=BuildStrategy(), backend='CINN'
|
||||
)(x)
|
||||
self.assert_nest_match(dy_out, sot_out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,279 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from collections import OrderedDict
|
||||
|
||||
import numpy as np
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
class TestBasicFasterGuard(unittest.TestCase):
|
||||
def test_lambda_guard(self):
|
||||
guard_lambda = paddle.framework.core.LambdaGuard(lambda x: x == 1)
|
||||
self.assertTrue(guard_lambda.check(1))
|
||||
self.assertFalse(guard_lambda.check(2))
|
||||
|
||||
def test_type_match_guard(self):
|
||||
guard_int = paddle.framework.core.TypeMatchGuard(int)
|
||||
guard_str = paddle.framework.core.TypeMatchGuard(str)
|
||||
guard_list = paddle.framework.core.TypeMatchGuard(list)
|
||||
self.assertTrue(guard_int.check(1))
|
||||
self.assertFalse(guard_int.check("1"))
|
||||
self.assertTrue(guard_str.check("1"))
|
||||
self.assertFalse(guard_str.check(1))
|
||||
self.assertTrue(guard_list.check([1]))
|
||||
self.assertFalse(guard_list.check(1))
|
||||
|
||||
def test_isinstance_match_guard(self):
|
||||
guard_int = paddle.framework.core.InstanceCheckGuard(int)
|
||||
guard_str = paddle.framework.core.InstanceCheckGuard(str)
|
||||
guard_list = paddle.framework.core.InstanceCheckGuard(list)
|
||||
guard_int_bool = paddle.framework.core.InstanceCheckGuard((int, bool))
|
||||
guard_int_str = paddle.framework.core.InstanceCheckGuard((int, str))
|
||||
self.assertTrue(guard_int.check(1))
|
||||
self.assertFalse(guard_int.check("1"))
|
||||
self.assertTrue(guard_str.check("1"))
|
||||
self.assertFalse(guard_str.check(1))
|
||||
self.assertTrue(guard_list.check([1]))
|
||||
self.assertFalse(guard_list.check(1))
|
||||
self.assertTrue(guard_int_bool.check(1))
|
||||
self.assertTrue(guard_int_bool.check(True))
|
||||
self.assertFalse(guard_int_bool.check("1"))
|
||||
self.assertTrue(guard_int_str.check(1))
|
||||
self.assertTrue(guard_int_str.check("1"))
|
||||
self.assertTrue(guard_int_str.check(True))
|
||||
self.assertFalse(guard_int_str.check([1]))
|
||||
|
||||
def test_value_match_guard(self):
|
||||
guard_value = paddle.framework.core.ValueMatchGuard(1)
|
||||
guard_container_value = paddle.framework.core.ValueMatchGuard([1])
|
||||
self.assertTrue(guard_value.check(1))
|
||||
self.assertFalse(guard_value.check(2))
|
||||
self.assertTrue(guard_container_value.check([1]))
|
||||
self.assertFalse(guard_container_value.check([2]))
|
||||
|
||||
def test_length_match_guard(self):
|
||||
guard_length = paddle.framework.core.LengthMatchGuard(1)
|
||||
# list
|
||||
self.assertTrue(guard_length.check([1]))
|
||||
self.assertFalse(guard_length.check([1, 2]))
|
||||
|
||||
# dict
|
||||
order_dict = OrderedDict()
|
||||
order_dict[1] = 2
|
||||
self.assertTrue(guard_length.check(order_dict))
|
||||
self.assertTrue(guard_length.check({1: 2}))
|
||||
|
||||
# tuple
|
||||
self.assertTrue(guard_length.check((1,)))
|
||||
self.assertFalse(guard_length.check((1, 2)))
|
||||
|
||||
def test_dtype_match_guard(self):
|
||||
guard_dtype = paddle.framework.core.DtypeMatchGuard(paddle.int32)
|
||||
self.assertTrue(
|
||||
guard_dtype.check(paddle.to_tensor(1, dtype=paddle.int32))
|
||||
)
|
||||
self.assertFalse(
|
||||
guard_dtype.check(paddle.to_tensor(1, dtype=paddle.float32))
|
||||
)
|
||||
|
||||
def test_shape_match_guard(self):
|
||||
tensor = paddle.randn([2, 3])
|
||||
guard_shape = paddle.framework.core.ShapeMatchGuard([2, 3], 0)
|
||||
self.assertTrue(guard_shape.check(tensor))
|
||||
guard_shape = paddle.framework.core.ShapeMatchGuard([2, None], 0)
|
||||
self.assertTrue(guard_shape.check(tensor))
|
||||
guard_shape = paddle.framework.core.ShapeMatchGuard([3, 2], 0)
|
||||
self.assertFalse(guard_shape.check(tensor))
|
||||
guard_shape = paddle.framework.core.ShapeMatchGuard([2, 3, 1], 0)
|
||||
self.assertFalse(guard_shape.check(tensor))
|
||||
guard_shape = paddle.framework.core.ShapeMatchGuard([2, None], 2)
|
||||
self.assertTrue(guard_shape.check(paddle.randn([2, 2])))
|
||||
guard_shape = paddle.framework.core.ShapeMatchGuard([2, None], 2)
|
||||
self.assertFalse(guard_shape.check(paddle.randn([2, 1])))
|
||||
|
||||
def test_attribute_match_guard(self):
|
||||
a = range(1, 10, 2)
|
||||
guard_attribute = paddle.framework.core.AttributeMatchGuard(a, "start")
|
||||
self.assertTrue(guard_attribute.check(a))
|
||||
self.assertFalse(guard_attribute.check(range(10)))
|
||||
|
||||
def test_layer_match_guard(self):
|
||||
layer = paddle.nn.Linear(10, 10)
|
||||
guard_layer = paddle.framework.core.LayerMatchGuard(layer)
|
||||
self.assertTrue(guard_layer.check(layer))
|
||||
self.assertFalse(guard_layer.check(paddle.nn.Linear(10, 10)))
|
||||
layer.eval()
|
||||
self.assertFalse(guard_layer.check(layer))
|
||||
layer.train()
|
||||
self.assertTrue(guard_layer.check(layer))
|
||||
|
||||
def test_id_match_guard(self):
|
||||
layer = paddle.nn.Linear(10, 10)
|
||||
guard_id = paddle.framework.core.IdMatchGuard(layer)
|
||||
self.assertTrue(guard_id.check(layer))
|
||||
layer.eval()
|
||||
self.assertTrue(guard_id.check(layer))
|
||||
self.assertFalse(guard_id.check(paddle.nn.Linear(10, 10)))
|
||||
|
||||
def test_numpy_dtype_match_guard(self):
|
||||
np_array = np.array(1, dtype=np.int32)
|
||||
guard_numpy_dtype = paddle.framework.core.NumPyDtypeMatchGuard(
|
||||
np_array.dtype
|
||||
)
|
||||
self.assertTrue(guard_numpy_dtype.check(np_array))
|
||||
self.assertTrue(guard_numpy_dtype.check(np.array(1, dtype=np.int32)))
|
||||
self.assertTrue(guard_numpy_dtype.check(np.int32()))
|
||||
self.assertFalse(guard_numpy_dtype.check(np.array(1, dtype=np.int64)))
|
||||
self.assertFalse(guard_numpy_dtype.check(np.float32()))
|
||||
self.assertFalse(guard_numpy_dtype.check(np.bool_()))
|
||||
|
||||
np_bool = np.bool_(1)
|
||||
guard_numpy_bool_dtype = paddle.framework.core.NumPyDtypeMatchGuard(
|
||||
np_bool.dtype
|
||||
)
|
||||
self.assertTrue(guard_numpy_bool_dtype.check(np.bool_()))
|
||||
self.assertTrue(
|
||||
guard_numpy_bool_dtype.check(np.array(1, dtype=np.bool_))
|
||||
)
|
||||
|
||||
def test_numpu_array_shape_match_guard(self):
|
||||
np_array = np.array([1, 2])
|
||||
guard_numpy_array_shape = (
|
||||
paddle.framework.core.NumPyArrayShapeMatchGuard(np_array.shape, 0)
|
||||
)
|
||||
self.assertTrue(guard_numpy_array_shape.check(np_array))
|
||||
self.assertTrue(
|
||||
guard_numpy_array_shape.check(np.array([1, 2], dtype=np.int32))
|
||||
)
|
||||
self.assertTrue(guard_numpy_array_shape.check(np.array([3, 4])))
|
||||
self.assertTrue(
|
||||
guard_numpy_array_shape.check(np.array([3, 4], dtype=np.float32))
|
||||
)
|
||||
self.assertFalse(guard_numpy_array_shape.check(np.array([[1], [2]])))
|
||||
self.assertFalse(guard_numpy_array_shape.check(np.array([1, 2, 3])))
|
||||
|
||||
np_array = np.array([1, None])
|
||||
guard_numpy_array_shape = (
|
||||
paddle.framework.core.NumPyArrayShapeMatchGuard(np_array.shape, 0)
|
||||
)
|
||||
self.assertTrue(guard_numpy_array_shape.check(np_array))
|
||||
self.assertTrue(guard_numpy_array_shape.check(np.array([2, 3])))
|
||||
self.assertFalse(guard_numpy_array_shape.check(np.array([2, 3, 4])))
|
||||
|
||||
np_array = np.array(1)
|
||||
guard_numpy_array_shape = (
|
||||
paddle.framework.core.NumPyArrayShapeMatchGuard(np_array.shape, 0)
|
||||
)
|
||||
self.assertTrue(guard_numpy_array_shape.check(np_array))
|
||||
self.assertTrue(
|
||||
guard_numpy_array_shape.check(np.array(2, dtype=np.int32))
|
||||
)
|
||||
self.assertTrue(
|
||||
guard_numpy_array_shape.check(np.array(3, dtype=np.float32))
|
||||
)
|
||||
self.assertFalse(guard_numpy_array_shape.check(np.array([1])))
|
||||
|
||||
def test_numpy_array_match_guard(self):
|
||||
np_array = paddle.framework.core.NumPyArrayValueMatchGuard(
|
||||
np.array([1, 2, 3])
|
||||
)
|
||||
self.assertTrue(np_array.check(np.array([1, 2, 3])))
|
||||
self.assertFalse(np_array.check(np.array([4, 5, 6])))
|
||||
|
||||
np_array_all_one = paddle.framework.core.NumPyArrayValueMatchGuard(
|
||||
np.array([1, 1, 1])
|
||||
)
|
||||
self.assertTrue(np_array_all_one.check(np.array([1, 1, 1])))
|
||||
self.assertFalse(np_array_all_one.check(np.array([1, 2, 3])))
|
||||
self.assertTrue(np_array_all_one.check(np.array([1, 1, 1], dtype=bool)))
|
||||
self.assertTrue(np_array_all_one.check(np.array([True, True, True])))
|
||||
self.assertTrue(np_array_all_one.check(np.array([1, 1, 1], dtype=int)))
|
||||
|
||||
np_bool_array = paddle.framework.core.NumPyArrayValueMatchGuard(
|
||||
np.array([True, False, True])
|
||||
)
|
||||
self.assertTrue(np_bool_array.check(np.array([True, False, True])))
|
||||
self.assertFalse(np_bool_array.check(np.array([True, True, True])))
|
||||
self.assertFalse(np_bool_array.check(np.array([False, False, False])))
|
||||
self.assertFalse(np_bool_array.check(np.array([1, 2, 3])))
|
||||
self.assertTrue(np_bool_array.check(np.array([True, False, 1])))
|
||||
self.assertFalse(np_bool_array.check(np.array([1, 2, 3], dtype=bool)))
|
||||
self.assertFalse(np_bool_array.check(np.array([1, 2, 3], dtype=int)))
|
||||
|
||||
np_bool_array_all_true = (
|
||||
paddle.framework.core.NumPyArrayValueMatchGuard(
|
||||
np.array([True, True, True])
|
||||
)
|
||||
)
|
||||
self.assertTrue(
|
||||
np_bool_array_all_true.check(np.array([True, True, True]))
|
||||
)
|
||||
self.assertFalse(
|
||||
np_bool_array_all_true.check(np.array([True, False, True]))
|
||||
)
|
||||
self.assertFalse(
|
||||
np_bool_array_all_true.check(np.array([False, False, False]))
|
||||
)
|
||||
self.assertFalse(np_bool_array_all_true.check(np.array([1, 2, 3])))
|
||||
self.assertTrue(np_bool_array_all_true.check(np.array([True, True, 1])))
|
||||
|
||||
def test_object_match_guard(self):
|
||||
def test_func():
|
||||
return 1 + 1
|
||||
|
||||
guard_object = paddle.framework.core.WeakRefMatchGuard(test_func)
|
||||
self.assertTrue(guard_object.check(test_func))
|
||||
self.assertFalse(guard_object.check(lambda x: x == 1))
|
||||
self.assertFalse(guard_object.check(1))
|
||||
self.assertFalse(guard_object.check("1"))
|
||||
|
||||
def test_is_dense_tensor_hold_allocation(self):
|
||||
tensor = paddle.to_tensor([1, 2, 3])
|
||||
guard = paddle.framework.core.IsNotDenseTensorHoldAllocationMatchGuard()
|
||||
self.assertEqual(
|
||||
guard.check(tensor), not tensor._is_dense_tensor_hold_allocation()
|
||||
)
|
||||
|
||||
|
||||
class TestFasterGuardGroup(unittest.TestCase):
|
||||
def test_guard_group(self):
|
||||
guard_lambda = paddle.framework.core.LambdaGuard(lambda x: x == 1)
|
||||
guard_type_match = paddle.framework.core.TypeMatchGuard(int)
|
||||
guard_group = paddle.framework.core.GuardGroup(
|
||||
[guard_type_match, guard_lambda] * 10
|
||||
)
|
||||
self.assertTrue(guard_group.check(1))
|
||||
self.assertFalse(guard_group.check(2))
|
||||
|
||||
def test_nested_guard_group(self):
|
||||
guard_lambda = paddle.framework.core.LambdaGuard(lambda x: x == 1)
|
||||
guard_type_match = paddle.framework.core.TypeMatchGuard(int)
|
||||
guard_group = paddle.framework.core.GuardGroup(
|
||||
[guard_type_match, guard_lambda]
|
||||
)
|
||||
for _ in range(10):
|
||||
guard_group = paddle.framework.core.GuardGroup(
|
||||
[guard_group, guard_type_match, guard_lambda]
|
||||
)
|
||||
self.assertTrue(guard_group.check(1))
|
||||
self.assertFalse(guard_group.check(2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,63 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
|
||||
|
||||
def fn_randint(x):
|
||||
x = x + 1
|
||||
x = x + random.randint(0, 100)
|
||||
x = x + 2
|
||||
return x
|
||||
|
||||
|
||||
def fn_random(x):
|
||||
x = x + 3
|
||||
x = x + random.random()
|
||||
x = x + 4
|
||||
return x
|
||||
|
||||
|
||||
class TestRandom(TestCaseBase):
|
||||
def test_random_randint(self):
|
||||
x = paddle.to_tensor(2024)
|
||||
|
||||
random.seed(2025)
|
||||
sym_output = symbolic_translate(fn_randint)(x)
|
||||
random.seed(2025)
|
||||
paddle_output = fn_randint(x)
|
||||
|
||||
self.assertEqual(sym_output, paddle_output)
|
||||
|
||||
def test_random_random(self):
|
||||
x = paddle.to_tensor(2025)
|
||||
|
||||
random.seed(2025)
|
||||
sym_output = symbolic_translate(fn_random)(x)
|
||||
random.seed(2025)
|
||||
paddle_output = fn_random(x)
|
||||
|
||||
self.assertEqual(sym_output, paddle_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,77 @@
|
||||
# Copyright (c) 2025 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
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit import sot
|
||||
|
||||
|
||||
class EmbeddingLayer(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.embedding = paddle.nn.Embedding(10, 10)
|
||||
|
||||
def forward(self, x):
|
||||
x = x + 1 - 1
|
||||
x = self.embedding(x)
|
||||
return x + 1
|
||||
|
||||
|
||||
def call_embedding_layer(x: paddle.Tensor, layer: paddle.nn.Layer):
|
||||
return layer(x)
|
||||
|
||||
|
||||
def call_functional_embedding(x: paddle.Tensor, weight: paddle.Tensor):
|
||||
x = x + 1 - 1
|
||||
x = paddle.nn.functional.embedding(x, weight)
|
||||
return x + 1
|
||||
|
||||
|
||||
class TestForceDynamic(TestCaseBase):
|
||||
def test_embedding_layer(self):
|
||||
paddle.jit.marker.force_dynamic(paddle.nn.Embedding)
|
||||
|
||||
layer = EmbeddingLayer()
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(
|
||||
call_embedding_layer,
|
||||
paddle.randint(0, 10, [1, 3, 224, 224], dtype='int64'),
|
||||
layer,
|
||||
)
|
||||
self.assertGreater(ctx.translate_count, 1)
|
||||
|
||||
sot.utils.paddle_api_config.break_graph_layer_classes.clear()
|
||||
|
||||
def test_functional_embedding(self):
|
||||
paddle.jit.marker.force_dynamic(paddle.nn.functional.embedding)
|
||||
|
||||
weight = paddle.randn([10, 10])
|
||||
x = paddle.randint(0, 10, [1, 3, 224, 224], dtype='int64')
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(call_functional_embedding, x, weight)
|
||||
self.assertGreater(ctx.translate_count, 1)
|
||||
|
||||
sot.utils.paddle_api_config.break_graph_functions.clear()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,171 @@
|
||||
# Copyright (c) 2025 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 operator
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils.exceptions import InnerError
|
||||
|
||||
|
||||
@functools.lru_cache
|
||||
def fn_with_cache(x):
|
||||
return x + 1
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def fn_with_lru_cache(x: paddle.Tensor):
|
||||
a1 = fn_with_cache(1)
|
||||
b1 = fn_with_cache(x)
|
||||
b2 = fn_with_cache(x)
|
||||
a2 = fn_with_cache(1)
|
||||
c1 = fn_with_cache(2)
|
||||
c2 = fn_with_cache(2)
|
||||
return a1, a2, b1, b2, c1, c2
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def try_reduce(fn, var, init=None):
|
||||
if init:
|
||||
ans = functools.reduce(fn, var, init)
|
||||
else:
|
||||
ans = functools.reduce(fn, var)
|
||||
return ans
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def try_reduce_iter(fn, var, init=None):
|
||||
ans = functools.reduce(fn, iter(var))
|
||||
return ans
|
||||
|
||||
|
||||
def add(a, b, c, d=2, e=3, f=4):
|
||||
return a, b, c, d, e, f
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def simple_partial(x=1):
|
||||
partial_func = functools.partial(add, x)
|
||||
out = partial_func(2, 3)
|
||||
return out
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def simple_partial_with_two_args(x=1):
|
||||
partial_func = functools.partial(add, x, 2)
|
||||
out = partial_func(3)
|
||||
return out
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def simple_partial_with_n_args(x=1):
|
||||
partial_func = functools.partial(add, x, 2, 3, 4, 5, 6)
|
||||
out = partial_func()
|
||||
return out
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def simple_partial_with_n_args_kwargs():
|
||||
partial_func = functools.partial(add, 1, 2, d=2)
|
||||
out = partial_func(paddle.to_tensor(3), e=7)
|
||||
return out
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def simple_partial_with_n_args_same_kwargs():
|
||||
partial_func = functools.partial(add, 1, 2, e=2)
|
||||
out = partial_func(3, e=7)
|
||||
return out
|
||||
|
||||
|
||||
# NOTE(DrRyanHuang): Currently, SOT does not support tensor bind yet
|
||||
# because this case is not common enough.
|
||||
# We could create a PartialClassVariable to prevent breakgraph.
|
||||
def simple_partial_with_tensor_bind():
|
||||
partial_func = functools.partial(add, 1, paddle.to_tensor(2.0), e=2)
|
||||
out = partial_func(3, e=7)
|
||||
return out
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def try_reduce_iter_failed(fn, var):
|
||||
it = iter(var)
|
||||
for _ in it:
|
||||
pass
|
||||
ans = functools.reduce(fn, it)
|
||||
return ans
|
||||
|
||||
|
||||
class TestFunctools(TestCaseBase):
|
||||
def test_lru_cache(self):
|
||||
x = paddle.rand([2, 3, 4])
|
||||
self.assert_results(fn_with_lru_cache, x)
|
||||
|
||||
def test_reduce_list(self):
|
||||
self.assert_results(try_reduce, lambda acc, x: acc + x, [1, 3, 4])
|
||||
|
||||
def test_reduce_dict(self):
|
||||
d1 = {"a": 1, "b": 2}
|
||||
d2 = {"a": 3, "c": 4}
|
||||
self.assert_results(try_reduce, lambda a, b: {**a, **b}, [d1, d2])
|
||||
|
||||
def test_reduce_tuple(self):
|
||||
self.assert_results(try_reduce, lambda acc, x: acc * x, (1, 3, 4))
|
||||
|
||||
def test_reduce_iter(self):
|
||||
f = lambda acc, x: acc + x
|
||||
l = [1, 2, 3]
|
||||
self.assert_results(try_reduce_iter, f, l)
|
||||
self.assert_exceptions(
|
||||
InnerError,
|
||||
r".*reduce\(\) of empty iterable with no initial value.*",
|
||||
try_reduce_iter_failed,
|
||||
f,
|
||||
l,
|
||||
)
|
||||
|
||||
def test_reduce_with_init_value(self):
|
||||
self.assert_results(try_reduce, lambda acc, x: acc + x, [1, 3, 4], -2)
|
||||
|
||||
def test_reduce_with_builtin_fn(self):
|
||||
self.assert_results(try_reduce, operator.add, [2, 5, 8])
|
||||
|
||||
def test_simple_partial(self):
|
||||
self.assert_results(simple_partial, 1)
|
||||
self.assert_results(simple_partial, 2)
|
||||
|
||||
def test_simple_partial_with_two_argsn(self):
|
||||
self.assert_results(simple_partial_with_two_args)
|
||||
|
||||
def test_simple_partial_with_n_args(self):
|
||||
self.assert_results(simple_partial_with_n_args)
|
||||
|
||||
def test_simple_partial_with_n_args_kwargs(self):
|
||||
self.assert_results(simple_partial_with_n_args_kwargs)
|
||||
|
||||
def test_simple_partial_with_n_args_same_kwargs(self):
|
||||
self.assert_results(simple_partial_with_n_args_same_kwargs)
|
||||
|
||||
def test_simple_partial_with_tensor_bind(self):
|
||||
self.assert_results(simple_partial_with_tensor_bind)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,97 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.opcode_translator.executor.executor_cache import (
|
||||
OpcodeExecutorCache,
|
||||
)
|
||||
from paddle.jit.sot.utils import ENV_SOT_UNSAFE_CACHE_FASTPATH
|
||||
from paddle.utils.environments import (
|
||||
EnvironmentVariableGuard,
|
||||
)
|
||||
|
||||
|
||||
def add(x, y):
|
||||
return x + y
|
||||
|
||||
|
||||
def subtract(x, y):
|
||||
return x - y
|
||||
|
||||
|
||||
class TestUnsafeCacheFastPath(TestCaseBase):
|
||||
def test_guard(self):
|
||||
# NOTE: When UNSAFE CACHE FASTPATH is enabled, if the same cache entry is hit consecutively
|
||||
# for 32 times (this threshold is configurable), the cache is considered stable and
|
||||
# subsequent guard checks will be skipped to improve performance.
|
||||
# The related logic is implemented in the OpcodeExecutorCache class.
|
||||
with EnvironmentVariableGuard(ENV_SOT_UNSAFE_CACHE_FASTPATH, True):
|
||||
self.assertTrue(ENV_SOT_UNSAFE_CACHE_FASTPATH.get())
|
||||
|
||||
self.assertFalse(
|
||||
OpcodeExecutorCache().is_fastpath_threshold_reached(
|
||||
add.__code__
|
||||
)
|
||||
)
|
||||
# The test needs to consider the issue of dynamic shapes: when the input shape changes,
|
||||
# the previous cache may become invalid.
|
||||
self.assert_results(add, 1, paddle.ones([32, 4]))
|
||||
for _ in range(34):
|
||||
self.assert_results(add, 1, paddle.ones([4]))
|
||||
self.assertTrue(
|
||||
OpcodeExecutorCache().is_fastpath_threshold_reached(
|
||||
add.__code__
|
||||
)
|
||||
)
|
||||
# NOTE: Once fastpath is enabled, the cache will not be rebuilt even if the shape changes again afterwards.
|
||||
# This is the "UNSAFE" aspect of the environment variable `ENV_SOT_UNSAFE_CACHE_FASTPATH`.
|
||||
self.assert_results(add, 1, paddle.ones([31, 4]))
|
||||
self.assertTrue(
|
||||
OpcodeExecutorCache().is_fastpath_threshold_reached(
|
||||
add.__code__
|
||||
)
|
||||
)
|
||||
|
||||
self.assertFalse(
|
||||
OpcodeExecutorCache().is_fastpath_threshold_reached(
|
||||
subtract.__code__
|
||||
)
|
||||
)
|
||||
|
||||
with EnvironmentVariableGuard(ENV_SOT_UNSAFE_CACHE_FASTPATH, False):
|
||||
self.assertFalse(ENV_SOT_UNSAFE_CACHE_FASTPATH.get())
|
||||
self.assertFalse(
|
||||
OpcodeExecutorCache().is_fastpath_threshold_reached(
|
||||
subtract.__code__
|
||||
)
|
||||
)
|
||||
for _ in range(35):
|
||||
self.assert_results(add, 1, 2)
|
||||
self.assertFalse(
|
||||
OpcodeExecutorCache().is_fastpath_threshold_reached(
|
||||
subtract.__code__
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,43 @@
|
||||
# Copyright (c) 2026 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
class TestGuardIsGradEnabled(TestCaseBase):
|
||||
def test_switch_is_grad_enabled(self):
|
||||
def fn(x):
|
||||
return x + 1
|
||||
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
with paddle.no_grad():
|
||||
self.assert_results(fn, 1)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
with paddle.enable_grad():
|
||||
self.assert_results(fn, 1)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,78 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def non_operator_related_fn(x: int, y: int):
|
||||
return x + y
|
||||
|
||||
|
||||
def partial_non_operator_related_fn(x: paddle.Tensor, y: paddle.Tensor, z: int):
|
||||
a = x + y
|
||||
return [a, z + z]
|
||||
|
||||
|
||||
def guard_inputs(x: int, y: int, z: int):
|
||||
return x + y + z
|
||||
|
||||
|
||||
class TestGuardOutputs(TestCaseBase):
|
||||
def test_non_operator_related_fn(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(non_operator_related_fn, 1, 2)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(non_operator_related_fn, 3, 4)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_partial_non_operator_related_fn(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(
|
||||
partial_non_operator_related_fn,
|
||||
paddle.to_tensor(1),
|
||||
paddle.to_tensor(2),
|
||||
3,
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(
|
||||
partial_non_operator_related_fn,
|
||||
paddle.to_tensor(4),
|
||||
paddle.to_tensor(5),
|
||||
6,
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_guard_inputs(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(guard_inputs, 1, 2, 3)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(guard_inputs, 0, 2, 3)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(guard_inputs, 1, 0, 3)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
self.assert_results(guard_inputs, 1, 2, 0)
|
||||
self.assertEqual(ctx.translate_count, 4)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,120 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.opcode_translator.custom_code import CustomCode
|
||||
|
||||
if TYPE_CHECKING:
|
||||
import types
|
||||
from collections.abc import Callable
|
||||
|
||||
z = paddle.to_tensor(1)
|
||||
|
||||
|
||||
def guard_tree(
|
||||
callback: Callable[[types.FrameType], CustomCode],
|
||||
):
|
||||
def foo(x, y):
|
||||
return x, y, z
|
||||
|
||||
def inner(x, y):
|
||||
paddle.framework.core.set_eval_frame(callback)
|
||||
try:
|
||||
return foo(x, y)
|
||||
finally:
|
||||
paddle.framework.core.set_eval_frame(None)
|
||||
|
||||
return inner
|
||||
|
||||
|
||||
class TestGuardTree(unittest.TestCase):
|
||||
def test_guard_tree(self):
|
||||
def callback(frame, **kwargs):
|
||||
guard_int = paddle.framework.core.TypeMatchGuard(int)
|
||||
guard_tensor = paddle.framework.core.TypeMatchGuard(
|
||||
type(paddle.to_tensor(1))
|
||||
)
|
||||
guard_tensor_shape_eq = paddle.framework.core.ValueMatchGuard(
|
||||
paddle.to_tensor([1]).shape
|
||||
)
|
||||
guard_eq = paddle.framework.core.ValueMatchGuard(1)
|
||||
|
||||
node_expr_x = paddle.framework.core.LocalVarExprNode("x")
|
||||
node_expr_y = paddle.framework.core.LocalVarExprNode("y")
|
||||
node_expr_z = paddle.framework.core.GlobalVarExprNode("z")
|
||||
node_expr_y_shape = paddle.framework.core.AttributeExprNode(
|
||||
node_expr_y, "shape"
|
||||
)
|
||||
node_expr_const_1 = paddle.framework.core.ConstantExprNode(1)
|
||||
|
||||
node_guard_x_type_match_int = paddle.framework.core.GuardNode(
|
||||
guard_int, [node_expr_x]
|
||||
)
|
||||
node_guard_x_eq_1 = paddle.framework.core.GuardNode(
|
||||
guard_eq, [node_expr_x]
|
||||
)
|
||||
node_guard_y_type_match_int = paddle.framework.core.GuardNode(
|
||||
guard_int, [node_expr_y]
|
||||
)
|
||||
node_guard_y_type_match_tensor = paddle.framework.core.GuardNode(
|
||||
guard_tensor, [node_expr_y]
|
||||
)
|
||||
node_guard_y_tensor_shape = paddle.framework.core.GuardNode(
|
||||
guard_tensor_shape_eq, [node_expr_y_shape]
|
||||
)
|
||||
node_guard_z_type_match_tensor = paddle.framework.core.GuardNode(
|
||||
guard_tensor, [node_expr_z]
|
||||
)
|
||||
node_guard_1_eq_1 = paddle.framework.core.GuardNode(
|
||||
guard_eq, [node_expr_const_1]
|
||||
)
|
||||
|
||||
guard_tree = paddle.framework.core.GuardTree(
|
||||
[
|
||||
[node_guard_x_eq_1],
|
||||
[node_guard_x_type_match_int, node_guard_y_type_match_int],
|
||||
[
|
||||
node_guard_x_type_match_int,
|
||||
node_guard_y_type_match_tensor,
|
||||
node_guard_y_tensor_shape,
|
||||
],
|
||||
[node_guard_z_type_match_tensor],
|
||||
[node_guard_1_eq_1],
|
||||
]
|
||||
)
|
||||
self.assertEqual(guard_tree.lookup(frame), target)
|
||||
return CustomCode(frame.f_code, False)
|
||||
|
||||
global z
|
||||
foo = guard_tree(callback)
|
||||
target = 0
|
||||
foo(1, 1)
|
||||
target = 1
|
||||
foo(2, 2)
|
||||
target = 2
|
||||
foo(2, paddle.to_tensor([2]))
|
||||
target = 3
|
||||
foo(2, 1.0)
|
||||
z = 1
|
||||
target = 4
|
||||
foo(2, 1.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,88 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def test_guard_fn(fn, inp):
|
||||
if fn is None:
|
||||
return 0
|
||||
else:
|
||||
return fn(inp)
|
||||
|
||||
|
||||
class TestGuardOutputs(TestCaseBase):
|
||||
def test_non_operator_related_fn(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(
|
||||
test_guard_fn,
|
||||
paddle.nn.functional.relu,
|
||||
paddle.to_tensor([1.0, -1.0]),
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(
|
||||
test_guard_fn,
|
||||
paddle.nn.functional.gelu,
|
||||
paddle.to_tensor([1.0, -1.0]),
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(
|
||||
test_guard_fn,
|
||||
paddle.nn.functional.relu,
|
||||
paddle.to_tensor([-1.0, -1.0]),
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(
|
||||
test_guard_fn, None, paddle.to_tensor([-1.0, -1.0])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
|
||||
deleted_cnt = 0
|
||||
|
||||
class Callable:
|
||||
def __call__(self, var):
|
||||
return paddle.nn.functional.relu(var)
|
||||
|
||||
def __del__(self):
|
||||
nonlocal deleted_cnt
|
||||
deleted_cnt += 1
|
||||
|
||||
fn1 = Callable()
|
||||
fn2 = Callable()
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(
|
||||
test_guard_fn, fn1, paddle.to_tensor([1.0, -1.0])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(
|
||||
test_guard_fn, fn2, paddle.to_tensor([1.0, -1.0])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(
|
||||
test_guard_fn, fn2, paddle.to_tensor([1.0, -1.0])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,121 @@
|
||||
# Copyright (c) 2025 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 random
|
||||
import string
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
from paddle.jit.sot.utils.exceptions import (
|
||||
BuiltinFunctionBreak,
|
||||
DataDependencyControlFlowBreak,
|
||||
DataDependencyDynamicShapeBreak,
|
||||
DataDependencyOperationBreak,
|
||||
DygraphInconsistentWithStaticBreak,
|
||||
FallbackInlineCallBreak,
|
||||
InferMetaBreak,
|
||||
InlineCallBreak,
|
||||
OtherInlineCallBreak,
|
||||
PsdbBreakReason,
|
||||
SideEffectBreak,
|
||||
UnsupportedIteratorBreak,
|
||||
UnsupportedPaddleAPIBreak,
|
||||
)
|
||||
from paddle.jit.sot.utils.info_collector import (
|
||||
BreakGraphReasonInfo,
|
||||
InfoBase,
|
||||
SubGraphInfo,
|
||||
)
|
||||
|
||||
generate_random_string = lambda N: ''.join(
|
||||
random.choices(string.ascii_uppercase + string.digits, k=N)
|
||||
)
|
||||
|
||||
|
||||
class TestSerialize(TestCaseBase):
|
||||
def test_case(self):
|
||||
x_dict = {
|
||||
'a': 'b',
|
||||
'c': 'd',
|
||||
}
|
||||
|
||||
x_str = InfoBase.serialize(x_dict)
|
||||
y_dict = InfoBase.deserialize(x_str)
|
||||
|
||||
self.assertEqual(x_dict, y_dict)
|
||||
|
||||
|
||||
class TestBreakGraphReasonInfo(TestCaseBase):
|
||||
def test_case(self):
|
||||
history = [
|
||||
BreakGraphReasonInfo(
|
||||
BreakReasonClass(
|
||||
reason_str=generate_random_string(random.randint(1, 5))
|
||||
)
|
||||
)
|
||||
for BreakReasonClass in [
|
||||
FallbackInlineCallBreak,
|
||||
DataDependencyControlFlowBreak,
|
||||
DataDependencyDynamicShapeBreak,
|
||||
DataDependencyOperationBreak,
|
||||
UnsupportedPaddleAPIBreak,
|
||||
BuiltinFunctionBreak,
|
||||
SideEffectBreak,
|
||||
UnsupportedIteratorBreak,
|
||||
InlineCallBreak,
|
||||
OtherInlineCallBreak,
|
||||
DygraphInconsistentWithStaticBreak,
|
||||
PsdbBreakReason,
|
||||
InferMetaBreak,
|
||||
]
|
||||
]
|
||||
|
||||
serialized = BreakGraphReasonInfo.json_report(history)
|
||||
deserialized = BreakGraphReasonInfo.restore_from_string(
|
||||
serialized.removeprefix("<sot>").removesuffix("</sot>")
|
||||
)
|
||||
|
||||
origin_reasons_dict, _ = BreakGraphReasonInfo.classify(history)
|
||||
origin_reasons2count = {
|
||||
k: len(v) for k, v in origin_reasons_dict.items()
|
||||
}
|
||||
|
||||
new_reasons_dict, _ = BreakGraphReasonInfo.classify(deserialized)
|
||||
new_reasons2count = {k: len(v) for k, v in new_reasons_dict.items()}
|
||||
|
||||
self.assertEqual(origin_reasons2count, new_reasons2count)
|
||||
|
||||
|
||||
class TestSubGraphInfo(TestCaseBase):
|
||||
def test_case(self):
|
||||
history = [
|
||||
SubGraphInfo(
|
||||
generate_random_string(random.randint(1, 5)),
|
||||
random.randint(0, 20),
|
||||
generate_random_string(random.randint(1, 5)),
|
||||
),
|
||||
] * 10
|
||||
|
||||
serialized = SubGraphInfo.json_report(history)
|
||||
deserialized = SubGraphInfo.restore_from_string(
|
||||
serialized.removeprefix("<sot>").removesuffix("</sot>")
|
||||
)
|
||||
|
||||
self.assertEqual(history, deserialized)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,149 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
def simple(x, y):
|
||||
x[0] = 3.0
|
||||
z = [y]
|
||||
y[1] = 5.0
|
||||
return x[0] + x[1] + z[0][1] + y[0] + y[1]
|
||||
|
||||
|
||||
def inplace_in_if(x, y, z):
|
||||
if z:
|
||||
x[0] = 3.0
|
||||
z = [y]
|
||||
y[1] = 5.0
|
||||
ret = x[0] + x[1] + z[0][1] + y[0] + y[1]
|
||||
return ret
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def inplace_in_if_fallback(x, y, z):
|
||||
if z > 0:
|
||||
x[0] = 3.0
|
||||
z = [y]
|
||||
y[1] = 5.0
|
||||
ret = x[0] + x[1] + z[0][1] + y[0] + y[1]
|
||||
return ret
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def inplace_in_loop(x, y):
|
||||
ret = 0
|
||||
for i in range(10):
|
||||
x[0] = 1
|
||||
z = [y]
|
||||
y[1] = 2 * i + 1
|
||||
ret += x[0] + x[1] + z[0][1] + y[0] + y[1]
|
||||
return ret
|
||||
|
||||
|
||||
def inplace_in_loop_fallback(x, y, it):
|
||||
ret = 0
|
||||
for i in it:
|
||||
x[0] = 1
|
||||
z = [y]
|
||||
y[1] = 2 * i + 1
|
||||
ret += x[0] + x[1] + z[0][1] + y[0] + y[1]
|
||||
return ret
|
||||
|
||||
|
||||
def inplace_case_0(x):
|
||||
x[:] = 1.0
|
||||
return x
|
||||
|
||||
|
||||
def inplace_case_1(x):
|
||||
x[0][0, 0::2] = 1.0
|
||||
return x
|
||||
|
||||
|
||||
def inplace_case_2(x):
|
||||
t = x[0]
|
||||
t[:, 0::2] = t[:, 0::2] * 0
|
||||
t[:, 1::2] = t[:, 1::2] + 2
|
||||
return x
|
||||
|
||||
|
||||
class TestInplaceApi(TestCaseBase):
|
||||
def test_case(self):
|
||||
self.assert_results(inplace_case_0, paddle.randn((1, 4)))
|
||||
self.assert_results(inplace_case_1, [paddle.randn((1, 4))])
|
||||
self.assert_results(inplace_case_2, [paddle.randn((1, 4))])
|
||||
|
||||
def test_backward(self):
|
||||
@symbolic_translate
|
||||
def func(x):
|
||||
m = x * 2
|
||||
n = x * 3
|
||||
y = m
|
||||
y[:] = n
|
||||
return y
|
||||
|
||||
x = paddle.ones((1, 4)) * 4
|
||||
x.stop_gradient = False
|
||||
y = func(x)
|
||||
y.sum().backward()
|
||||
assert (x.grad.numpy() == 3).all()
|
||||
|
||||
def test_simple(self):
|
||||
self.assert_results(
|
||||
simple, paddle.to_tensor([1.0, 2.0]), paddle.to_tensor([3.0, 4.0])
|
||||
)
|
||||
|
||||
def test_if(self):
|
||||
self.assert_results(
|
||||
inplace_in_if,
|
||||
paddle.to_tensor([1.0, 2.0]),
|
||||
paddle.to_tensor([3.0, 4.0]),
|
||||
True,
|
||||
)
|
||||
self.assert_results(
|
||||
inplace_in_if_fallback,
|
||||
paddle.to_tensor([1.0, 2.0]),
|
||||
paddle.to_tensor([3.0, 4.0]),
|
||||
paddle.to_tensor(1),
|
||||
)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_loop(self):
|
||||
self.assert_results(
|
||||
inplace_in_loop,
|
||||
paddle.to_tensor([1.0, 2.0]),
|
||||
paddle.to_tensor([3.0, 4.0]),
|
||||
)
|
||||
|
||||
a = range(10)
|
||||
sym_output = symbolic_translate(inplace_in_loop_fallback)(
|
||||
paddle.to_tensor([1.0, 2.0]), paddle.to_tensor([3.0, 4.0]), iter(a)
|
||||
)
|
||||
paddle_output = inplace_in_loop_fallback(
|
||||
paddle.to_tensor([1.0, 2.0]), paddle.to_tensor([3.0, 4.0]), iter(a)
|
||||
)
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,188 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import random
|
||||
import unittest
|
||||
from typing import TYPE_CHECKING
|
||||
from unittest.mock import patch
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.opcode_translator.custom_code import CustomCode
|
||||
from paddle.jit.sot.opcode_translator.executor.executor_cache import (
|
||||
OpcodeExecutorCache,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from types import FrameType
|
||||
|
||||
|
||||
def fake_frames() -> tuple[
|
||||
FrameType,
|
||||
FrameType,
|
||||
FrameType,
|
||||
FrameType,
|
||||
FrameType,
|
||||
]:
|
||||
def fake_inner_fn_1():
|
||||
frame = inspect.currentframe()
|
||||
assert frame is not None
|
||||
return frame
|
||||
|
||||
def fake_inner_fn_2():
|
||||
frame = inspect.currentframe()
|
||||
assert frame is not None
|
||||
return frame
|
||||
|
||||
def fake_inner_fn_3():
|
||||
frame = inspect.currentframe()
|
||||
assert frame is not None
|
||||
return frame
|
||||
|
||||
def fake_inner_fn_4():
|
||||
frame = inspect.currentframe()
|
||||
assert frame is not None
|
||||
return frame
|
||||
|
||||
def fake_inner_fn_5():
|
||||
frame = inspect.currentframe()
|
||||
assert frame is not None
|
||||
return frame
|
||||
|
||||
return (
|
||||
fake_inner_fn_1(),
|
||||
fake_inner_fn_2(),
|
||||
fake_inner_fn_3(),
|
||||
fake_inner_fn_4(),
|
||||
fake_inner_fn_5(),
|
||||
)
|
||||
|
||||
|
||||
(
|
||||
FRAME_1,
|
||||
FRAME_2,
|
||||
FRAME_3,
|
||||
FRAME_4,
|
||||
FRAME_5,
|
||||
) = fake_frames()
|
||||
|
||||
|
||||
class GuardCode:
|
||||
def __init__(self, recompile):
|
||||
self.func = lambda frame: recompile
|
||||
self.mirror_guard = self.func
|
||||
self.expr = f"lambda frame: {recompile}"
|
||||
self.inlined_expr = f"lambda frame: {recompile}"
|
||||
self.__globals__ = {}
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self.func(*args, **kwargs)
|
||||
|
||||
|
||||
def mock_start_translate(frame: FrameType, **kwargs):
|
||||
translate_map = {
|
||||
FRAME_1: (
|
||||
CustomCode(FRAME_2.f_code, False),
|
||||
GuardCode(True),
|
||||
[paddle.framework.core.DummyGuardNode()],
|
||||
),
|
||||
FRAME_3: (
|
||||
CustomCode(FRAME_4.f_code, False),
|
||||
GuardCode(False),
|
||||
[paddle.framework.core.DummyGuardNode(False)],
|
||||
), # Always re-compile
|
||||
FRAME_5: (
|
||||
CustomCode(None, False),
|
||||
lambda frame: True,
|
||||
[paddle.framework.core.DummyGuardNode()],
|
||||
),
|
||||
}
|
||||
return translate_map[frame]
|
||||
|
||||
|
||||
class TestOpcodeExecutorCache(unittest.TestCase):
|
||||
def reset(self):
|
||||
global translate_count
|
||||
translate_count = 0
|
||||
OpcodeExecutorCache().clear()
|
||||
|
||||
@patch(
|
||||
"paddle.jit.sot.opcode_translator.executor.executor_cache.start_translate",
|
||||
mock_start_translate,
|
||||
)
|
||||
def test_cache_hit(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
translated_code_1 = OpcodeExecutorCache()(FRAME_1)
|
||||
assert translated_code_1 is not None
|
||||
self.assertEqual(translated_code_1.code, FRAME_2.f_code)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
# cache hit
|
||||
translated_code_2 = OpcodeExecutorCache()(FRAME_1)
|
||||
assert translated_code_2 is not None
|
||||
self.assertEqual(translated_code_2.code, FRAME_2.f_code)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
@patch(
|
||||
"paddle.jit.sot.opcode_translator.executor.executor_cache.start_translate",
|
||||
mock_start_translate,
|
||||
)
|
||||
def test_cache_miss_due_to_unknown_code(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
translated_code_1 = OpcodeExecutorCache()(FRAME_1)
|
||||
assert translated_code_1 is not None
|
||||
self.assertEqual(translated_code_1.code, FRAME_2.f_code)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
# cache miss
|
||||
translated_code_2 = OpcodeExecutorCache()(FRAME_3)
|
||||
assert translated_code_2 is not None
|
||||
self.assertEqual(translated_code_2.code, FRAME_4.f_code)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
@patch(
|
||||
"paddle.jit.sot.opcode_translator.executor.executor_cache.start_translate",
|
||||
mock_start_translate,
|
||||
)
|
||||
def test_cache_miss_due_to_check_failed(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
translated_code_1 = OpcodeExecutorCache()(FRAME_3)
|
||||
assert translated_code_1 is not None
|
||||
self.assertEqual(translated_code_1.code, FRAME_4.f_code)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
# cache miss
|
||||
translated_code_2 = OpcodeExecutorCache()(FRAME_3)
|
||||
assert translated_code_2 is not None
|
||||
self.assertEqual(translated_code_2.code, FRAME_4.f_code)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
def foo(x):
|
||||
return x + 1
|
||||
|
||||
|
||||
class TestCacheExceedLimit(TestCaseBase):
|
||||
def test_cache_exceed_limit(self):
|
||||
for _ in range(30):
|
||||
input = random.random()
|
||||
self.assert_results(foo, input)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,104 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
class ListIterable:
|
||||
def __init__(self):
|
||||
self._list = [1, 2, 3]
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._list)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def list_iterable(x: paddle.Tensor):
|
||||
iterable = ListIterable()
|
||||
for i in iterable:
|
||||
x += i
|
||||
return x
|
||||
|
||||
|
||||
class TupleIterable:
|
||||
def __init__(self):
|
||||
self._tuple = (1, 2, 3)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._tuple)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def tuple_iterable(x: paddle.Tensor):
|
||||
iterable = TupleIterable()
|
||||
for i in iterable:
|
||||
x += i
|
||||
return x
|
||||
|
||||
|
||||
class DictIterable:
|
||||
def __init__(self):
|
||||
self._dict = {0: 1, 1: 2, 2: 3}
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._dict)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dict_iterable(x: paddle.Tensor):
|
||||
iterable = DictIterable()
|
||||
for i in iterable:
|
||||
x += i
|
||||
return x
|
||||
|
||||
|
||||
class RangeIterable:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __iter__(self):
|
||||
return iter(range(5))
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def range_iterable(x: paddle.Tensor):
|
||||
iterable = RangeIterable()
|
||||
for i in iterable:
|
||||
x += i
|
||||
return x
|
||||
|
||||
|
||||
class TestIterable(TestCaseBase):
|
||||
def test_list_iterable(self):
|
||||
self.assert_results(list_iterable, paddle.to_tensor(0))
|
||||
|
||||
def test_tuple_iterable(self):
|
||||
self.assert_results(tuple_iterable, paddle.to_tensor(0))
|
||||
|
||||
def test_dict_iterable(self):
|
||||
self.assert_results(dict_iterable, paddle.to_tensor(0))
|
||||
|
||||
def test_range_iterable(self):
|
||||
self.assert_results(range_iterable, paddle.to_tensor(0))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,163 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot.utils import min_graph_size_guard, strict_mode_guard
|
||||
|
||||
|
||||
def case_for(x, vars):
|
||||
x = x + 1
|
||||
sot.psdb.breakgraph()
|
||||
for y in vars:
|
||||
x += y
|
||||
return x
|
||||
|
||||
|
||||
def case_if(x):
|
||||
x = x + 1
|
||||
if x > 5:
|
||||
x += 3
|
||||
else:
|
||||
x += 4
|
||||
return x
|
||||
|
||||
|
||||
def case_call(x):
|
||||
y = paddle.to_tensor(x.numpy())
|
||||
x += y
|
||||
return x
|
||||
|
||||
|
||||
def call_with_kwargs_inner(x):
|
||||
return paddle.to_tensor(x.numpy())
|
||||
|
||||
|
||||
def call_with_kwargs(x):
|
||||
y = call_with_kwargs_inner(x=x)
|
||||
x += y
|
||||
return x
|
||||
|
||||
|
||||
def case_all(x, vars):
|
||||
x = x + 1
|
||||
for y in vars:
|
||||
z = paddle.to_tensor(x.numpy())
|
||||
x += z
|
||||
x += y
|
||||
if x > 5:
|
||||
x += y
|
||||
else:
|
||||
x += 3
|
||||
return x
|
||||
|
||||
|
||||
class CustomLayer(paddle.nn.Layer):
|
||||
def forward(self, x):
|
||||
return self.forward_features(x)
|
||||
|
||||
def forward_features(self, x):
|
||||
return x.numpy()
|
||||
|
||||
|
||||
def get_arg_from_kwargs(x, **kwargs):
|
||||
x = x if x is not None else None
|
||||
y = kwargs.get("y", None)
|
||||
paddle.jit.sot.psdb.breakgraph()
|
||||
return x, y
|
||||
|
||||
|
||||
def add_with_breakgraph(x, y):
|
||||
sot.psdb.breakgraph()
|
||||
return x + y
|
||||
|
||||
|
||||
def restore_same_arg_when_fallback(x):
|
||||
return add_with_breakgraph(x, x)
|
||||
|
||||
|
||||
def trim_trailing_to_bool(x, y):
|
||||
return x and y
|
||||
|
||||
|
||||
def always_use_load_fast_with_strong_ref(x):
|
||||
y = x + 1
|
||||
# In this case, originally y will be load with LOAD_FAST_BORROW
|
||||
# When breakgraph, the y on the stack, it will be stored and loaded with LOAD_FAST
|
||||
# But since y is not a strong ref, it may be GCed before loaded again
|
||||
# We add a pass to make sure y is a strong ref, so it will not be GCed
|
||||
# when loaded again.
|
||||
_stack_ref = (y, paddle.jit.sot.psdb.breakgraph())
|
||||
x = y + 1
|
||||
return x
|
||||
|
||||
|
||||
class TestMinGraphSize(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
@min_graph_size_guard(10)
|
||||
def test_cases(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(case_for, x, [1, 2, 3])
|
||||
self.assert_results(case_if, x)
|
||||
self.assert_results(case_call, x)
|
||||
self.assert_results(case_all, x, [4, 5, 6])
|
||||
|
||||
@min_graph_size_guard(10)
|
||||
def test_layer(self):
|
||||
x = paddle.to_tensor(1)
|
||||
layer = CustomLayer()
|
||||
self.assert_results(layer.forward, x)
|
||||
|
||||
@min_graph_size_guard(10)
|
||||
def test_layer_multiple_times(self):
|
||||
x = paddle.to_tensor(1)
|
||||
layer = CustomLayer()
|
||||
for _ in range(8):
|
||||
self.assert_results(layer.forward, x)
|
||||
|
||||
@min_graph_size_guard(10)
|
||||
def test_call_with_kwargs(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(call_with_kwargs, x)
|
||||
|
||||
@min_graph_size_guard(10)
|
||||
def test_get_arg_from_kwargs(self):
|
||||
self.assert_results(get_arg_from_kwargs, None)
|
||||
self.assert_results(get_arg_from_kwargs, None, y=1)
|
||||
|
||||
@min_graph_size_guard(10)
|
||||
def test_restore_same_arg_when_fallback(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(restore_same_arg_when_fallback, x)
|
||||
|
||||
@min_graph_size_guard(10)
|
||||
def test_trim_trailing_to_bool(self):
|
||||
x = paddle.to_tensor(False)
|
||||
y = paddle.to_tensor(False)
|
||||
self.assert_results(trim_trailing_to_bool, x, y)
|
||||
|
||||
@min_graph_size_guard(10)
|
||||
def test_always_use_load_fast_with_strong_ref(self):
|
||||
x = paddle.to_tensor(1)
|
||||
self.assert_results(always_use_load_fast_with_strong_ref, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,82 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.symbolic.compile_cache import CompileSIRCache
|
||||
|
||||
|
||||
class SimpleNet(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.dropout = paddle.nn.Dropout(p=0.5)
|
||||
|
||||
def forward(self, x):
|
||||
if self.training:
|
||||
out1 = paddle.nn.functional.dropout(x, p=0.5, training=True)
|
||||
else:
|
||||
out1 = paddle.nn.functional.dropout(x, p=0.5, training=False)
|
||||
out1 = self.dropout(out1)
|
||||
return out1
|
||||
|
||||
|
||||
class TestModelSwitchTraining(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.seed = 1127
|
||||
self.net = SimpleNet()
|
||||
# singleton
|
||||
self.compile_cache = CompileSIRCache()
|
||||
|
||||
def check_mode(self, is_train):
|
||||
self.assertEqual(len(self.compile_cache.cache), 1)
|
||||
mode = next(
|
||||
iter(self.compile_cache.cache.values())
|
||||
).partial_program.training
|
||||
self.assertEqual(mode, is_train)
|
||||
|
||||
def get_dygraph_out(self, input):
|
||||
paddle.seed(self.seed)
|
||||
self.net.eval()
|
||||
eval_result = self.net(input)
|
||||
self.net.train()
|
||||
train_result = self.net(input)
|
||||
return eval_result, train_result
|
||||
|
||||
def get_static_out(self, input):
|
||||
paddle.seed(self.seed)
|
||||
self.compile_cache.clear()
|
||||
static_net = paddle.jit.to_static(self.net, full_graph=False)
|
||||
static_net.eval()
|
||||
eval_result = static_net(input)
|
||||
self.check_mode(is_train=False)
|
||||
self.compile_cache.clear()
|
||||
|
||||
static_net.train()
|
||||
train_result = static_net(input)
|
||||
self.check_mode(is_train=True)
|
||||
return eval_result, train_result
|
||||
|
||||
def test_model_switch_training(self):
|
||||
input = paddle.rand((10, 10))
|
||||
dygraph_eval, dygraph_train = self.get_dygraph_out(input)
|
||||
static_eval, static_train = self.get_static_out(input)
|
||||
np.testing.assert_allclose(dygraph_eval.numpy(), static_eval.numpy())
|
||||
np.testing.assert_allclose(dygraph_train.numpy(), static_train.numpy())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def foo(x, y):
|
||||
ret = x + y
|
||||
return ret
|
||||
|
||||
|
||||
class TestMultipleArgs(TestCaseBase):
|
||||
def test_multiple_args(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
y = paddle.to_tensor([2.0])
|
||||
self.assert_results(foo, x, y)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,353 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from paddle.jit.sot.opcode_translator.executor.mutable_data import (
|
||||
MutableData,
|
||||
MutableDictLikeData,
|
||||
MutableListLikeData,
|
||||
)
|
||||
|
||||
|
||||
class VariableBase:
|
||||
def __init__(self): ...
|
||||
|
||||
|
||||
class ConstVariable(VariableBase):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
def __repr__(self):
|
||||
return f"ConstVariable({self.value})"
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, ConstVariable):
|
||||
return False
|
||||
return self.value == other.value
|
||||
|
||||
|
||||
class DictVariable(VariableBase):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.proxy = MutableDictLikeData(data, DictVariable.proxy_getter)
|
||||
|
||||
@staticmethod
|
||||
def proxy_getter(proxy, key):
|
||||
if key not in proxy.original_data:
|
||||
return MutableData.Empty()
|
||||
return ConstVariable(proxy.original_data[key])
|
||||
|
||||
def getitem(self, key):
|
||||
res = self.proxy.get(key)
|
||||
if isinstance(res, MutableData.Empty):
|
||||
raise KeyError(f"Key {key} not found")
|
||||
return res
|
||||
|
||||
def setitem(self, key, value):
|
||||
self.proxy.set(key, value)
|
||||
|
||||
def delitem(self, key):
|
||||
self.proxy.delete(key)
|
||||
|
||||
|
||||
class ListVariable(VariableBase):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
self.proxy = MutableListLikeData(data, ListVariable.proxy_getter)
|
||||
|
||||
@staticmethod
|
||||
def proxy_getter(proxy, key):
|
||||
if key < 0 or key >= len(proxy.original_data):
|
||||
return MutableData.Empty()
|
||||
return ConstVariable(proxy.original_data[key])
|
||||
|
||||
def getitem(self, key):
|
||||
if isinstance(key, int):
|
||||
res = self.proxy.get(key)
|
||||
if isinstance(res, MutableData.Empty):
|
||||
raise IndexError(f"Index {key} out of range")
|
||||
return res
|
||||
elif isinstance(key, slice):
|
||||
return self.proxy.get_all()[key]
|
||||
else:
|
||||
raise TypeError(f"Invalid key type {type(key)}")
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.getitem(key)
|
||||
|
||||
def setitem(self, key, value):
|
||||
if isinstance(key, int):
|
||||
self.proxy.set(key, value)
|
||||
elif isinstance(key, slice):
|
||||
start, end, step = key.indices(self.proxy.length)
|
||||
indices = list(range(start, end, step))
|
||||
if step == 1:
|
||||
# replace a continuous range
|
||||
for i, idx in enumerate(indices):
|
||||
self.proxy.delete(idx - i)
|
||||
for i, item in enumerate(value):
|
||||
self.proxy.insert(start + i, item)
|
||||
else:
|
||||
# replace some elements
|
||||
if len(indices) != len(value):
|
||||
raise ValueError(
|
||||
f"Attempt to replace {len(indices)} items with {len(value)}"
|
||||
)
|
||||
for i, idx in enumerate(indices):
|
||||
self.proxy.set(idx, value[i])
|
||||
|
||||
def delitem(self, key):
|
||||
self.proxy.delete(key)
|
||||
|
||||
def insert(self, index, value):
|
||||
self.proxy.insert(index, value)
|
||||
|
||||
def append(self, value):
|
||||
self.proxy.insert(self.proxy.length, value)
|
||||
|
||||
def extend(self, value):
|
||||
for item in value:
|
||||
self.append(item)
|
||||
|
||||
def pop(self, index=-1):
|
||||
res = self.getitem(index)
|
||||
self.delitem(index)
|
||||
return res
|
||||
|
||||
def clear(self):
|
||||
for i in range(self.proxy.length):
|
||||
self.delitem(0)
|
||||
|
||||
def remove(self, value):
|
||||
for i in range(self.proxy.length):
|
||||
if self.getitem(i) == value:
|
||||
self.delitem(i)
|
||||
return
|
||||
raise ValueError(f"Value {value} not found")
|
||||
|
||||
def sort(self, key=None, reverse=False):
|
||||
if key is None:
|
||||
key = lambda x: x
|
||||
permutation = list(range(self.proxy.length))
|
||||
permutation.sort(
|
||||
key=lambda x: key(self.getitem(x).value), reverse=reverse
|
||||
)
|
||||
self.proxy.permutate(permutation)
|
||||
|
||||
def reverse(self):
|
||||
permutation = list(range(self.proxy.length))
|
||||
permutation.reverse()
|
||||
self.proxy.permutate(permutation)
|
||||
|
||||
|
||||
class TestMutableDictLikeVariable(unittest.TestCase):
|
||||
def test_getitem(self):
|
||||
data = {"a": 1, "b": 2}
|
||||
var = DictVariable(data)
|
||||
self.assertEqual(var.getitem("a"), ConstVariable(1))
|
||||
self.assertEqual(var.getitem("b"), ConstVariable(2))
|
||||
|
||||
def test_setitem(self):
|
||||
data = {"a": 1, "b": 2}
|
||||
var = DictVariable(data)
|
||||
var.setitem("a", ConstVariable(3))
|
||||
self.assertEqual(var.getitem("a"), ConstVariable(3))
|
||||
var.setitem("c", ConstVariable(4))
|
||||
self.assertEqual(var.getitem("c"), ConstVariable(4))
|
||||
|
||||
def test_delitem(self):
|
||||
data = {"a": 1, "b": 2}
|
||||
var = DictVariable(data)
|
||||
var.delitem("a")
|
||||
with self.assertRaises(KeyError):
|
||||
var.getitem("a")
|
||||
|
||||
def test_keys(self):
|
||||
data = {"a": 1, "b": 2}
|
||||
var = DictVariable(data)
|
||||
self.assertEqual(list(var.proxy.get_all().keys()), ["a", "b"])
|
||||
|
||||
|
||||
class TestMutableListLikeVariable(unittest.TestCase):
|
||||
def test_getitem(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
self.assertEqual(var.getitem(0), ConstVariable(1))
|
||||
self.assertEqual(var.getitem(1), ConstVariable(2))
|
||||
self.assertEqual(var.getitem(2), ConstVariable(3))
|
||||
|
||||
def test_getitem_slice_1(self):
|
||||
data = [1, 2, 3, 4, 5, 6, 7]
|
||||
var = ListVariable(data)
|
||||
self.assertEqual(
|
||||
var.getitem(slice(0, 3)),
|
||||
[ConstVariable(1), ConstVariable(2), ConstVariable(3)],
|
||||
)
|
||||
self.assertEqual(
|
||||
var.getitem(slice(4, 1, -1)),
|
||||
[ConstVariable(5), ConstVariable(4), ConstVariable(3)],
|
||||
)
|
||||
self.assertEqual(
|
||||
var.getitem(slice(1, 5, 2)),
|
||||
[ConstVariable(2), ConstVariable(4)],
|
||||
)
|
||||
|
||||
def test_getitem_slice_2(self):
|
||||
data = [1, 2, 3, 4, 5, 6, 7]
|
||||
var = ListVariable(data)
|
||||
self.assertEqual(
|
||||
var[0:3],
|
||||
[ConstVariable(1), ConstVariable(2), ConstVariable(3)],
|
||||
)
|
||||
self.assertEqual(
|
||||
var[4:1:-1],
|
||||
[ConstVariable(5), ConstVariable(4), ConstVariable(3)],
|
||||
)
|
||||
self.assertEqual(
|
||||
var[1:5:2],
|
||||
[ConstVariable(2), ConstVariable(4)],
|
||||
)
|
||||
|
||||
def test_setitem(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
var.setitem(0, ConstVariable(4))
|
||||
self.assertEqual(var.getitem(0), ConstVariable(4))
|
||||
var.append(ConstVariable(5))
|
||||
self.assertEqual(var.getitem(3), ConstVariable(5))
|
||||
|
||||
def test_setitem_slice_1(self):
|
||||
data = [1, 2, 3, 4, 5, 6, 7]
|
||||
var = ListVariable(data)
|
||||
var.setitem(slice(0, 3), [ConstVariable(4), ConstVariable(5)])
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [4, 5, 4, 5, 6, 7]],
|
||||
)
|
||||
var.setitem(
|
||||
slice(4, 1, -1),
|
||||
[ConstVariable(8), ConstVariable(9), ConstVariable(10)],
|
||||
)
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [4, 5, 10, 9, 8, 7]],
|
||||
)
|
||||
|
||||
def test_setitem_slice_2(self):
|
||||
data = [1, 2, 3, 4, 5, 6, 7]
|
||||
var = ListVariable(data)
|
||||
var.setitem(slice(2, 5, 2), [ConstVariable(8), ConstVariable(9)])
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [1, 2, 8, 4, 9, 6, 7]],
|
||||
)
|
||||
|
||||
def test_delitem(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
var.delitem(0)
|
||||
with self.assertRaises(IndexError):
|
||||
var.getitem(2)
|
||||
var.pop()
|
||||
with self.assertRaises(IndexError):
|
||||
var.getitem(1)
|
||||
|
||||
def test_insert(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
var.insert(0, ConstVariable(4))
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [4, 1, 2, 3]],
|
||||
)
|
||||
var.insert(2, ConstVariable(5))
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [4, 1, 5, 2, 3]],
|
||||
)
|
||||
|
||||
def test_append(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
var.append(ConstVariable(4))
|
||||
self.assertEqual(var.getitem(3), ConstVariable(4))
|
||||
|
||||
def test_extend(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
var.extend([ConstVariable(4), ConstVariable(5)])
|
||||
self.assertEqual(var.getitem(3), ConstVariable(4))
|
||||
self.assertEqual(var.getitem(4), ConstVariable(5))
|
||||
|
||||
def test_pop(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
self.assertEqual(var.pop(), ConstVariable(3))
|
||||
self.assertEqual(var.pop(0), ConstVariable(1))
|
||||
|
||||
def test_clear(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
var.clear()
|
||||
self.assertEqual(var.proxy.length, 0)
|
||||
|
||||
def test_remove(self):
|
||||
data = [1, 2, 3]
|
||||
var = ListVariable(data)
|
||||
var.remove(ConstVariable(2))
|
||||
self.assertEqual(var.getitem(0), ConstVariable(1))
|
||||
self.assertEqual(var.getitem(1), ConstVariable(3))
|
||||
with self.assertRaises(ValueError):
|
||||
var.remove(ConstVariable(2))
|
||||
|
||||
def test_sort(self):
|
||||
data = [2, 3, 0, 4, 1, 5]
|
||||
var = ListVariable(data)
|
||||
var.sort()
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [0, 1, 2, 3, 4, 5]],
|
||||
)
|
||||
|
||||
def test_sort_with_key(self):
|
||||
data = [-1, -4, 2, 0, 5, -3]
|
||||
var = ListVariable(data)
|
||||
var.sort(key=lambda x: x**2)
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [0, -1, 2, -3, -4, 5]],
|
||||
)
|
||||
|
||||
def test_sort_reverse(self):
|
||||
data = [2, 3, 0, 4, 1, 5]
|
||||
var = ListVariable(data)
|
||||
var.sort(reverse=True)
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [5, 4, 3, 2, 1, 0]],
|
||||
)
|
||||
|
||||
def test_reverse(self):
|
||||
data = [2, 3, 0, 4, 1, 5]
|
||||
var = ListVariable(data)
|
||||
var.reverse()
|
||||
self.assertEqual(
|
||||
[var.getitem(i) for i in range(var.proxy.length)],
|
||||
[ConstVariable(n) for n in [5, 1, 4, 0, 3, 2]],
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,70 @@
|
||||
# Copyright (c) 2025 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
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
@paddle.no_grad()
|
||||
def inner_no_grad_fn(x, y):
|
||||
return x * y + x**2
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def no_grad_fn_caller(x, y):
|
||||
z = inner_no_grad_fn(x * y, y)
|
||||
a = x * y + x**3 - 1
|
||||
return z + a
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
@paddle.no_grad()
|
||||
def outer_no_grad_fn(x, y):
|
||||
z = x * y + x**2
|
||||
a = inner_no_grad_fn(x, y)
|
||||
return z + a
|
||||
|
||||
|
||||
class TestNoGrad(TestCaseBase):
|
||||
def test_inner_no_grad(self):
|
||||
x = paddle.randn([10, 3])
|
||||
y = paddle.randn([10, 3])
|
||||
x.stop_gradient = False
|
||||
y.stop_gradient = False
|
||||
self.assert_results_with_grad(
|
||||
[x, y],
|
||||
no_grad_fn_caller,
|
||||
x,
|
||||
y,
|
||||
)
|
||||
|
||||
def test_outer_no_grad(self):
|
||||
x = paddle.randn([1, 3])
|
||||
y = paddle.randn([1, 3])
|
||||
x.stop_gradient = False
|
||||
y.stop_gradient = False
|
||||
self.assert_results_with_grad(
|
||||
[x, y],
|
||||
outer_no_grad_fn,
|
||||
x,
|
||||
y,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,113 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
def numpy_add(x, y):
|
||||
out = paddle.to_tensor(x.numpy() + y.numpy())
|
||||
return out
|
||||
|
||||
|
||||
def tensor_add_numpy(x, y):
|
||||
ret = x + y
|
||||
return ret
|
||||
|
||||
|
||||
def large_numpy_array_to_tensor(x):
|
||||
return paddle.to_tensor(x)
|
||||
|
||||
|
||||
def normal_numpy_array_to_tensor(x):
|
||||
return paddle.to_tensor(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def numpy_api_with_number_calculation(t):
|
||||
a = np.log(2)
|
||||
b = np.exp(3)
|
||||
c = np.sqrt(4)
|
||||
d = np.ceil(5.1)
|
||||
e = np.add(1, 2)
|
||||
f = a + 1
|
||||
g = 1 - b
|
||||
h = c * 2
|
||||
i = int(a)
|
||||
j = float(b)
|
||||
k = c.item()
|
||||
l = t + d
|
||||
return a, b, c, d, e, f, g, h, i, j, k, l
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def numpy_bool(x: np.number):
|
||||
return bool(x == 1)
|
||||
|
||||
|
||||
class TestNumPy(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_numpy_add(self):
|
||||
x = paddle.to_tensor([2])
|
||||
y = paddle.to_tensor([3])
|
||||
self.assert_results(numpy_add, x, y)
|
||||
|
||||
def test_tensor_add_numpy_number(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
y = np.int64(2)
|
||||
self.assert_results(tensor_add_numpy, x, y)
|
||||
self.assert_results(tensor_add_numpy, y, x)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_tensor_add_numpy_array(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
y = np.array(2.0)
|
||||
self.assert_results(tensor_add_numpy, x, y)
|
||||
self.assert_results(tensor_add_numpy, y, x)
|
||||
|
||||
def test_large_numpy_array_to_tensor(self):
|
||||
# size should be larger than 1024*1024, because we throw an exception
|
||||
# when the size is larger than 1024*1024 in assign API (to_tensor static branch)
|
||||
x = np.random.rand(1024, 1024, 2).astype(np.float32)
|
||||
self.assert_results(large_numpy_array_to_tensor, x)
|
||||
|
||||
def test_numpy_array_guard(self):
|
||||
x = np.array([1.0, 2.0])
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(normal_numpy_array_to_tensor, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(normal_numpy_array_to_tensor, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
def test_numpy_api_with_number_calculation(self):
|
||||
t = paddle.to_tensor([1.0])
|
||||
self.assert_results(numpy_api_with_number_calculation, t)
|
||||
|
||||
def test_numpy_bool(self):
|
||||
x = np.float32(1.0)
|
||||
self.assert_results(numpy_bool, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,218 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def unary_api(func, x: np.ndarray, *args, **kwargs):
|
||||
return func(x, *args, **kwargs)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def binary_api(
|
||||
func: np.ufunc,
|
||||
x: np.ndarray | list,
|
||||
y: np.ndarray | list,
|
||||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
return func(x, y, *args, **kwargs)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def binary_operator(op: str, x: np.ndarray, y: np.ndarray):
|
||||
if op == "+":
|
||||
return x + y
|
||||
elif op == "-":
|
||||
return x - y
|
||||
elif op == "*":
|
||||
return x * y
|
||||
elif op == "/":
|
||||
return x / y
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def get_item(x: np.ndarray, index: int | tuple | np.ndarray):
|
||||
return x[index]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def set_item(
|
||||
x: np.ndarray,
|
||||
index: int | list | np.ndarray,
|
||||
value: int | list | np.ndarray,
|
||||
):
|
||||
x[index] = value
|
||||
return x
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def grad_fn(pd_x, np_y, np_y2):
|
||||
pd_y = paddle.to_tensor(np_y)
|
||||
pd_z = paddle.add(pd_x, pd_y)
|
||||
pd_y2 = paddle.to_tensor(np_y2).astype("float32")
|
||||
pd_z2 = paddle.matmul(pd_z, pd_y2)
|
||||
return pd_z2
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def demo(pd_x):
|
||||
np_y = np.array([[1, 2, 3], [4, 5, 6]])
|
||||
np_y2 = np.transpose(np_y)
|
||||
pd_y2 = paddle.to_tensor(np_y2)
|
||||
pd_z = paddle.matmul(pd_x, pd_y2)
|
||||
np_z = pd_z.numpy()
|
||||
np_z2 = np.mean(np_z)
|
||||
np_z3 = np.add(pd_x.numpy(), np_z2)
|
||||
np_z4 = np_z * np_z3[:, :2]
|
||||
pd_z2 = paddle.subtract(pd_z, paddle.to_tensor(np_z4))
|
||||
return pd_z2
|
||||
|
||||
|
||||
def absolute(x):
|
||||
return np.absolute(x)
|
||||
|
||||
|
||||
class TestNumPyArray(TestCaseBase):
|
||||
def test_guard(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(
|
||||
binary_api, np.add, np.array([1, 2]), np.array([3, 4])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(
|
||||
binary_api,
|
||||
np.add,
|
||||
np.array([1, 2], dtype=np.int32),
|
||||
np.array([3, 4], dtype=np.int32),
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(
|
||||
binary_api, np.add, np.array([1]), np.array([3])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
self.assert_results(
|
||||
binary_api, np.add, np.array([4, 3]), np.array([2, 1])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
|
||||
def test_gradient(self):
|
||||
pd_x = paddle.randn([2, 3], dtype="float32")
|
||||
pd_x.stop_gradient = False
|
||||
self.assert_results_with_grad(
|
||||
pd_x,
|
||||
grad_fn,
|
||||
pd_x,
|
||||
np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32),
|
||||
np.ones(shape=(3, 2)),
|
||||
)
|
||||
|
||||
def test_add_01(self):
|
||||
x = np.array([1, 2])
|
||||
y = np.array([3, 4])
|
||||
self.assert_results(binary_api, np.add, x, y)
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_add_02(self):
|
||||
x = [1, 2]
|
||||
y = [3, 4]
|
||||
self.assert_results(binary_api, np.add, x, y)
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_sub(self):
|
||||
x = np.array([1, 2])
|
||||
y = np.array([3, 4])
|
||||
self.assert_results(binary_api, np.subtract, x, y)
|
||||
self.assert_results(binary_api, np.subtract, [1, 2], [3, 4])
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_mul(self):
|
||||
x = np.array([1, 2])
|
||||
y = np.array([3, 4])
|
||||
self.assert_results(binary_api, np.multiply, x, y)
|
||||
self.assert_results(binary_api, np.multiply, [1, 2], [3, 4])
|
||||
self.assert_results_with_grad(binary_api, np.multiply, [1, 2], [3, 4])
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_div(self):
|
||||
x = np.array([1, 2])
|
||||
y = np.array([3, 4])
|
||||
self.assert_results(binary_api, np.divide, x, y)
|
||||
self.assert_results(binary_api, np.divide, [1, 2], [3, 4])
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_operator(self):
|
||||
x = np.array([1, 2])
|
||||
y = np.array([3, 4])
|
||||
self.assert_results(binary_operator, '+', x, y)
|
||||
self.assert_results(binary_operator, '-', x, y)
|
||||
self.assert_results(binary_operator, '*', x, y)
|
||||
self.assert_results(binary_operator, '/', x, y)
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_argmax(self):
|
||||
x = np.array([[1, 2], [3, 4]])
|
||||
self.assert_results(unary_api, np.argmax, x)
|
||||
self.assert_results(unary_api, np.argmax, x, axis=0)
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_sum(self):
|
||||
x = np.array([[1, 2], [3, 4]])
|
||||
self.assert_results(unary_api, np.sum, x)
|
||||
self.assert_results(unary_api, np.sum, x, axis=0)
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_getitem(self):
|
||||
x = np.array([[1, 2], [3, 4]])
|
||||
self.assert_results(get_item, x, 0)
|
||||
i = tuple(0, 0)
|
||||
self.assert_results(get_item, x, i)
|
||||
i2 = np.array([0, 1])
|
||||
self.assert_results(get_item, x, i2)
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_setitem(self):
|
||||
x = np.array([[1, 2], [3, 4]])
|
||||
y = np.array([5, 6])
|
||||
self.assert_results(set_item, x, 0, y)
|
||||
i = np.array([0])
|
||||
self.assert_results(set_item, x, i, y)
|
||||
self.assert_results(set_item, x, [0], [5, 6])
|
||||
|
||||
@unittest.skip("Not supported yet")
|
||||
def test_demo(self):
|
||||
pd_x = paddle.randn([2, 3], dtype="float32")
|
||||
pd_x.stop_gradient = False
|
||||
self.assert_results_with_grad(pd_x, demo, pd_x)
|
||||
|
||||
def test_absolute(self):
|
||||
x = np.array([[1, -2], [-3, 4]])
|
||||
self.assert_results(absolute, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_fallback
|
||||
from paddle.jit.sot.utils import ENV_MIN_GRAPH_SIZE
|
||||
|
||||
ENV_MIN_GRAPH_SIZE.set(-1)
|
||||
|
||||
|
||||
@check_no_fallback
|
||||
def forward(x, y):
|
||||
if x == 0:
|
||||
return y + 2
|
||||
else:
|
||||
return y * 2
|
||||
|
||||
|
||||
@check_no_fallback
|
||||
def forward2(x, y):
|
||||
if x == x: # numpy == numpy
|
||||
return y + 2
|
||||
else:
|
||||
return y * 2
|
||||
|
||||
|
||||
class TestJumpWithNumPy(TestCaseBase):
|
||||
def test_jump(self):
|
||||
self.assert_results(forward, np.array([1]), paddle.to_tensor(2))
|
||||
self.assert_results(forward, np.array([0]), paddle.to_tensor(2))
|
||||
self.assert_results(forward2, np.array([0]), paddle.to_tensor(2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,95 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def output_identity(x):
|
||||
return x
|
||||
|
||||
|
||||
def output_const():
|
||||
return 42
|
||||
|
||||
|
||||
def output_list(x: paddle.Tensor, y: paddle.Tensor, z: int):
|
||||
a = x + 1
|
||||
b = z + 1
|
||||
l = [1, a, b, y]
|
||||
return l
|
||||
|
||||
|
||||
def output_dict(x: paddle.Tensor, y: paddle.Tensor, z: int):
|
||||
a = x + 1
|
||||
b = z + 1
|
||||
l = {1: a, b: y}
|
||||
return l
|
||||
|
||||
|
||||
def output_dict_const_key(x: paddle.Tensor, y: paddle.Tensor, z: int):
|
||||
a = x + 1
|
||||
b = z + 1
|
||||
l = {1: a, 2: y}
|
||||
return l
|
||||
|
||||
|
||||
def output_nest_struct(x: paddle.Tensor, y: paddle.Tensor, z: int):
|
||||
a = x + y + z
|
||||
b = z + 1
|
||||
l = [1 + 1, (z, a), [b]]
|
||||
return l
|
||||
|
||||
|
||||
class TestOutputRestoration(TestCaseBase):
|
||||
def test_output_identity(self):
|
||||
self.assert_results(output_identity, 1)
|
||||
self.assert_results(output_identity, 2)
|
||||
self.assert_results(output_identity, paddle.to_tensor(1))
|
||||
|
||||
def test_output_const(self):
|
||||
self.assert_results(output_const)
|
||||
|
||||
def test_output_list(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
|
||||
self.assert_results(output_list, a, b, 3)
|
||||
|
||||
def test_output_dict(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
|
||||
self.assert_results(output_dict, a, b, 3)
|
||||
|
||||
def test_output_dict_const_key(self):
|
||||
a = paddle.to_tensor(2)
|
||||
b = paddle.to_tensor(3)
|
||||
|
||||
self.assert_results(output_dict_const_key, a, b, 4)
|
||||
|
||||
def test_output_nest_struct(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
|
||||
self.assert_results(output_nest_struct, a, b, 3)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,57 @@
|
||||
# Copyright (c) 2026 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 types
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
class ScaleOp:
|
||||
def __init__(self, weight, bias):
|
||||
self.weight = weight
|
||||
self.bias = bias
|
||||
|
||||
def apply(self, x):
|
||||
return x * self.weight + self.bias
|
||||
|
||||
|
||||
class Module(types.ModuleType):
|
||||
def __init__(self):
|
||||
super().__init__("module")
|
||||
_scale = ScaleOp(2, 3)
|
||||
self.scale = _scale.apply
|
||||
|
||||
|
||||
mod = Module()
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def call_patched_fn(x):
|
||||
return mod.scale(x)
|
||||
|
||||
|
||||
class TestCallPatchedFn(TestCaseBase):
|
||||
def test_call_patched_fn(self):
|
||||
x = paddle.randn([16, 72])
|
||||
self.assert_results(call_patched_fn, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,120 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import test_instruction_translator_cache_context
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import (
|
||||
psdb,
|
||||
symbolic_translate,
|
||||
)
|
||||
from paddle.jit.sot.utils.envs import strict_mode_guard
|
||||
from paddle.jit.sot.utils.exceptions import InnerError
|
||||
|
||||
|
||||
def assert_true_case(input: bool):
|
||||
psdb.assert_true(input)
|
||||
|
||||
|
||||
def breakgraph_case(x):
|
||||
x = x + 1
|
||||
psdb.breakgraph()
|
||||
x = x + 1
|
||||
return x
|
||||
|
||||
|
||||
def fallback_not_recursive_inner(x):
|
||||
x = x + 1
|
||||
x = x + 1
|
||||
return x
|
||||
|
||||
|
||||
def fallback_not_recursive_case(x):
|
||||
psdb.fallback(recursive=False)
|
||||
x = fallback_not_recursive_inner(x)
|
||||
return x
|
||||
|
||||
|
||||
def fallback_recursive_case(x):
|
||||
psdb.fallback(recursive=True)
|
||||
x = fallback_not_recursive_inner(x)
|
||||
return x
|
||||
|
||||
|
||||
@psdb.check_no_breakgraph
|
||||
def check_no_breakgraph_case(x):
|
||||
x = x + 1
|
||||
psdb.breakgraph()
|
||||
x = x + 1
|
||||
return x
|
||||
|
||||
|
||||
@psdb.check_no_fallback
|
||||
def check_no_fallback_case(x):
|
||||
x = x + 1
|
||||
psdb.fallback(recursive=False)
|
||||
x = x + 1
|
||||
return x
|
||||
|
||||
|
||||
class TestPsdb(unittest.TestCase):
|
||||
def test_assert_true(self):
|
||||
# Test with True
|
||||
symbolic_translate(assert_true_case)(True)
|
||||
|
||||
# Test with False
|
||||
with self.assertRaises(InnerError):
|
||||
symbolic_translate(assert_true_case)(False)
|
||||
|
||||
def test_breakgraph(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
symbolic_translate(breakgraph_case)(x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_fallback_not_recursive(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
symbolic_translate(fallback_not_recursive_case)(x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_fallback_recursive(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
symbolic_translate(fallback_recursive_case)(x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
def test_check_no_breakgraph(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
with self.assertRaises(InnerError):
|
||||
symbolic_translate(check_no_breakgraph_case)(x)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_check_no_fallback(self):
|
||||
x = paddle.to_tensor([1.0])
|
||||
with self.assertRaises(InnerError):
|
||||
symbolic_translate(check_no_fallback_case)(x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,36 @@
|
||||
# Copyright (c) 2025 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
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle.distributed as dist
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph, check_no_fallback
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
@check_no_fallback
|
||||
def forward():
|
||||
mesh = dist.ProcessMesh([[0, 1], [2, 3]], dim_names=['x', 'y'])
|
||||
placement = [dist.Shard(0), dist.Replicate(), dist.Partial()]
|
||||
|
||||
|
||||
class TestPureClass(TestCaseBase):
|
||||
def test_class(self):
|
||||
self.assert_results(forward)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,46 @@
|
||||
# Copyright (c) 2024 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
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def if_breakgraph(x, y):
|
||||
z = x + y
|
||||
if x:
|
||||
z = z + 1
|
||||
else:
|
||||
z = z - 1
|
||||
return z
|
||||
|
||||
|
||||
class TestResumeCache(TestCaseBase):
|
||||
def test_resume_cache_in_if_breakgraph(self):
|
||||
x = paddle.to_tensor(0)
|
||||
with test_instruction_translator_cache_context() as cache:
|
||||
self.assertEqual(cache.translate_count, 0)
|
||||
self.assert_results(if_breakgraph, x, 1)
|
||||
self.assertEqual(cache.translate_count, 2)
|
||||
self.assert_results(if_breakgraph, x, 2)
|
||||
self.assertEqual(cache.translate_count, 3)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,73 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
class Head(nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.head = nn.Linear(10, 150)
|
||||
|
||||
def forward(self, x, patch_embed_size):
|
||||
masks = self.head(x)
|
||||
# [b, (h w), c] -> [b, c, h, w]
|
||||
h, w = patch_embed_size[0], patch_embed_size[1]
|
||||
masks = masks.reshape((1, h, w, paddle.shape(masks)[-1]))
|
||||
masks = masks.transpose((0, 3, 1, 2))
|
||||
return masks
|
||||
|
||||
|
||||
class SimpleNet(nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.tmp = nn.Linear(1, 1024 * 10)
|
||||
self.tmp2 = nn.Linear(1, 1 * 10 * 32 * 32)
|
||||
self.head = Head()
|
||||
|
||||
def getshape(self, x):
|
||||
x = self.tmp2(x.mean().reshape([1])).reshape([1, 10, 32, 32])
|
||||
x = paddle.shape(x)
|
||||
return x
|
||||
|
||||
def forward(self, x):
|
||||
sot.psdb.fallback()
|
||||
shape = self.getshape(x)
|
||||
feat = self.tmp(x.mean().reshape([1])).reshape([1, 1024, 10])
|
||||
logits = self.head(feat, shape[2:])
|
||||
return logits
|
||||
|
||||
|
||||
class TestSegmentLinear(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_simple(self):
|
||||
x = paddle.randn((1, 8, 8))
|
||||
net = SimpleNet()
|
||||
net = paddle.jit.to_static(
|
||||
net, full_graph=False
|
||||
) # dont make effect. we need fetch sot PR in paddle.
|
||||
loss = net(x)
|
||||
loss = loss.sum()
|
||||
loss.backward()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,363 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
from paddle.jit.sot.utils import InnerError, strict_mode_guard
|
||||
|
||||
|
||||
def dict_setitem(x):
|
||||
x[0] = 1
|
||||
return x[0]
|
||||
|
||||
|
||||
def dict_delitem(x):
|
||||
del x[0]
|
||||
return x
|
||||
|
||||
|
||||
def dict_delitem_getitem(a):
|
||||
b = a[0]
|
||||
del a[0]
|
||||
b[0] = 1
|
||||
return a, b
|
||||
|
||||
|
||||
def dict_nested_1(x):
|
||||
x[0][0] = 42
|
||||
x[1][0] = x[0][0] + x[0][1]
|
||||
x[2] = {1: 2}
|
||||
return x
|
||||
|
||||
|
||||
def dict_nested_2(x):
|
||||
a = x[0]
|
||||
b = x[1]
|
||||
del a[0]
|
||||
a[1] = b[0]
|
||||
a[2] = b[1]
|
||||
x[1][0] = 42
|
||||
del a[1]
|
||||
return a, b
|
||||
|
||||
|
||||
def list_append_int(tensor_x, list_a):
|
||||
tensor_x = tensor_x + 1
|
||||
list_a.append(12)
|
||||
return tensor_x, list_a
|
||||
|
||||
|
||||
def list_append_tensor(tensor_x, list_a):
|
||||
tensor_x = tensor_x + 1
|
||||
list_a.append(tensor_x)
|
||||
return tensor_x, list_a
|
||||
|
||||
|
||||
def list_delitem(list_a):
|
||||
del list_a[0]
|
||||
return list_a[0]
|
||||
|
||||
|
||||
def list_extend(list_a):
|
||||
list_a.extend([1, 2, 3])
|
||||
return list_a[0]
|
||||
|
||||
|
||||
def list_nested(list_a):
|
||||
inner_list = []
|
||||
inner_list.append(list_a)
|
||||
inner_list[-1].append(12)
|
||||
return 12
|
||||
|
||||
|
||||
def list_insert(list_a):
|
||||
list_a.insert(0, 1)
|
||||
return list_a[0]
|
||||
|
||||
|
||||
def list_remove(list_a):
|
||||
list_a.remove(1)
|
||||
return list_a[0]
|
||||
|
||||
|
||||
def list_pop(list_a):
|
||||
list_a.pop(0)
|
||||
list_a.pop()
|
||||
list_a.pop(1)
|
||||
return list_a[0]
|
||||
|
||||
|
||||
def list_clear(list_a):
|
||||
list_a.clear()
|
||||
return list_a
|
||||
|
||||
|
||||
def list_sort(list_a):
|
||||
list_a.sort()
|
||||
return list_a
|
||||
|
||||
|
||||
def list_reverse(list_a):
|
||||
list_a.reverse()
|
||||
return list_a
|
||||
|
||||
|
||||
def slice_in_for_loop(x, iter_num=3):
|
||||
x = paddle.to_tensor(x)
|
||||
a = []
|
||||
|
||||
iter_num = paddle.full(shape=[1], fill_value=iter_num, dtype="int32")
|
||||
|
||||
for i in range(iter_num):
|
||||
a.append(x)
|
||||
|
||||
for i in range(iter_num):
|
||||
a[i] = x
|
||||
out = a[2]
|
||||
return out
|
||||
|
||||
|
||||
# TODO: Object SideEffect
|
||||
class CustomObject:
|
||||
def __init__(self):
|
||||
self.x = 2
|
||||
self.y = paddle.to_tensor(1)
|
||||
|
||||
def object_attr_set2(self, x):
|
||||
self.outputs = []
|
||||
self.outputs.append(x)
|
||||
return self.outputs
|
||||
|
||||
|
||||
@sot.psdb.check_no_breakgraph
|
||||
def object_attr_set(cus_obj, t):
|
||||
"""object side effect."""
|
||||
t = t + 1
|
||||
cus_obj.x = t
|
||||
return t, cus_obj.x
|
||||
|
||||
|
||||
def object_attr_breakgraph(cus_obj, t):
|
||||
t = t + 1
|
||||
sot.psdb.breakgraph()
|
||||
cus_obj.x = t
|
||||
sot.psdb.breakgraph()
|
||||
return t, cus_obj.x
|
||||
|
||||
|
||||
@sot.psdb.check_no_breakgraph
|
||||
def object_attr_tensor_del(cus_obj):
|
||||
del cus_obj.y
|
||||
|
||||
|
||||
@sot.psdb.check_no_breakgraph
|
||||
def object_attr_int_del(cus_obj):
|
||||
del cus_obj.x
|
||||
|
||||
|
||||
def slice_list_after_change(l):
|
||||
l.reverse()
|
||||
sum = 0
|
||||
for i, v in zip(range(2), l[2:]):
|
||||
sum += v
|
||||
return sum
|
||||
|
||||
|
||||
class ReadBufferAfterChanged(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.buffer1 = paddle.to_tensor(1)
|
||||
self.buffer2 = paddle.to_tensor(2)
|
||||
|
||||
def forward(self, x):
|
||||
self.buffer1 += 1
|
||||
return x + self.buffer1 + self.buffer2
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, ReadBufferAfterChanged):
|
||||
return False
|
||||
return paddle.equal(self.buffer1, other.buffer1) and paddle.equal(
|
||||
self.buffer2, other.buffer2
|
||||
)
|
||||
|
||||
|
||||
class TestDictSideEffect(TestCaseBase):
|
||||
def test_dict_setitem(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_setitem, {0: paddle.to_tensor(0)}
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
dict_setitem, {0: paddle.to_tensor(1)}
|
||||
)
|
||||
|
||||
def test_dict_delitem(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_delitem, {0: paddle.to_tensor(0), 1: paddle.to_tensor(1)}
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
dict_delitem, {0: paddle.to_tensor(1), 2: paddle.to_tensor(2)}
|
||||
)
|
||||
|
||||
def test_dict_delitem_getitem(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_delitem_getitem, {0: {0: 1, 1: 2}}
|
||||
)
|
||||
|
||||
def test_dict_nested_1(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_nested_1, {0: {0: 1, 1: 2}, 1: {0: 1, 1: 2}}
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
dict_nested_1, {0: {0: 123, 1: 2}, 1: {0: 1, 1: 2}}
|
||||
)
|
||||
|
||||
def test_dict_nested_2(self):
|
||||
self.assert_results_with_side_effects(
|
||||
dict_nested_2, {0: {0: 1, 1: 2}, 1: {0: 1, 1: 2}}
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
dict_nested_2, {0: {0: 123, 1: 2}, 1: {0: 1, 1: 2}}
|
||||
)
|
||||
|
||||
|
||||
class TestListSideEffect(TestCaseBase):
|
||||
def test_list_append(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_append_int, paddle.to_tensor(1), [1, 2, 3]
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
list_append_tensor, paddle.to_tensor(2), [1, 2, 3]
|
||||
)
|
||||
|
||||
def test_list_delitem(self):
|
||||
self.assert_results_with_side_effects(list_delitem, [1, 2, 3])
|
||||
|
||||
def test_list_extend(self):
|
||||
self.assert_results_with_side_effects(
|
||||
list_extend, [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
)
|
||||
|
||||
def test_list_insert(self):
|
||||
self.assert_results_with_side_effects(list_insert, [1, 2, 3])
|
||||
self.assert_results_with_side_effects(
|
||||
list_insert, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
|
||||
)
|
||||
|
||||
def test_list_remove(self):
|
||||
self.assert_results_with_side_effects(list_remove, [1, 1, 1])
|
||||
self.assert_results_with_side_effects(list_remove, [0, 1, 2])
|
||||
# TODO(DrRyanHuang): change this to ValueError
|
||||
with self.assertRaises(InnerError):
|
||||
symbolic_translate(list_remove)([0, 2, 4])
|
||||
|
||||
def test_list_pop(self):
|
||||
self.assert_results_with_side_effects(list_pop, [1, 2, 3, 4, 5])
|
||||
self.assert_results_with_side_effects(
|
||||
list_pop, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
|
||||
)
|
||||
|
||||
def test_list_clear(self):
|
||||
self.assert_results_with_side_effects(list_clear, [1, 2, 3, 4, 5])
|
||||
self.assert_results_with_side_effects(
|
||||
list_clear, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
|
||||
)
|
||||
|
||||
def test_list_sort(self):
|
||||
self.assert_results_with_side_effects(list_sort, [2, 1, 7, 3, 4, 6])
|
||||
self.assert_results_with_side_effects(
|
||||
list_sort, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
|
||||
)
|
||||
|
||||
def test_list_reverse(self):
|
||||
self.assert_results_with_side_effects(list_reverse, [1, 2, 3, 4, 5])
|
||||
self.assert_results_with_side_effects(
|
||||
list_reverse, [-1, 2, -3, 4, -5, 6, -7, 8, -9]
|
||||
)
|
||||
|
||||
def test_slice_in_for_loop(self):
|
||||
x = 2
|
||||
with strict_mode_guard(False):
|
||||
self.assert_results_with_side_effects(slice_in_for_loop, x)
|
||||
|
||||
def test_list_nested(self):
|
||||
self.assert_results_with_side_effects(list_nested, [1, 2, 3])
|
||||
|
||||
|
||||
class TestSliceAfterChange(TestCaseBase):
|
||||
def test_slice_list_after_change(self):
|
||||
self.assert_results_with_side_effects(
|
||||
slice_list_after_change, [1, 2, 3, 4]
|
||||
)
|
||||
self.assert_results_with_side_effects(
|
||||
slice_list_after_change, [7, 8, 9, 10]
|
||||
)
|
||||
|
||||
|
||||
class TestAttrSideEffect(TestCaseBase):
|
||||
def attr_check(self, func, attr_keys: list[str], cls, *inputs):
|
||||
cus_obj1 = cls()
|
||||
cus_obj2 = cls()
|
||||
sym_output = symbolic_translate(func)(cus_obj1, *inputs)
|
||||
paddle_output = func(cus_obj2, *inputs)
|
||||
for key in attr_keys:
|
||||
self.assert_nest_match(
|
||||
getattr(cus_obj1, key, f"__MISS_KEY__{key}"),
|
||||
getattr(cus_obj2, key, f"__MISS_KEY__{key}"),
|
||||
)
|
||||
self.assert_nest_match(sym_output, paddle_output)
|
||||
|
||||
def test_attr_set(self):
|
||||
self.attr_check(object_attr_set, ["x"], CustomObject, 5)
|
||||
self.attr_check(
|
||||
CustomObject.object_attr_set2, ["outputs"], CustomObject, 6
|
||||
)
|
||||
self.attr_check(
|
||||
CustomObject.object_attr_set2,
|
||||
["outputs"],
|
||||
CustomObject,
|
||||
paddle.to_tensor(5),
|
||||
)
|
||||
self.attr_check(
|
||||
object_attr_set, ["x"], CustomObject, paddle.to_tensor(5)
|
||||
)
|
||||
|
||||
def test_attr_del(self):
|
||||
self.attr_check(object_attr_tensor_del, ["y"], CustomObject)
|
||||
self.attr_check(object_attr_int_del, ["x"], CustomObject)
|
||||
|
||||
def test_attr_set_breakgraph(self):
|
||||
self.attr_check(object_attr_breakgraph, ["x"], CustomObject, 100)
|
||||
self.attr_check(object_attr_breakgraph, ["x"], CustomObject, 1000)
|
||||
|
||||
|
||||
class TestReadBufferAfterChanged(TestCaseBase):
|
||||
def test_read_buffer_after_change(self):
|
||||
layer = ReadBufferAfterChanged()
|
||||
x = paddle.randn([1, 2, 3])
|
||||
self.assert_results_with_side_effects(
|
||||
layer.__class__.forward,
|
||||
layer,
|
||||
x,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,90 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle import nn
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
class A:
|
||||
def __init__(self, vals):
|
||||
vals.append(1)
|
||||
|
||||
|
||||
def foo(x, y):
|
||||
out = nn.Softmax()(paddle.to_tensor([x, y], dtype="float32"))
|
||||
return out
|
||||
|
||||
|
||||
def foo2(x, y):
|
||||
t = nn.Softmax()
|
||||
out1 = t(paddle.to_tensor([x, y], dtype="float32"))
|
||||
out2 = t(paddle.to_tensor([x, y], dtype="float32"))
|
||||
return out1 + out2
|
||||
|
||||
|
||||
def error_foo(x):
|
||||
t = nn.Linear(10, 10)
|
||||
return t(x)
|
||||
|
||||
|
||||
class NopLayer(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.weight = None
|
||||
|
||||
|
||||
def created_layer_reconstruct():
|
||||
x = paddle.to_tensor([1, 2], dtype="float32")
|
||||
weight = NopLayer().weight
|
||||
if weight is not None:
|
||||
x += 1
|
||||
return x
|
||||
|
||||
|
||||
def bar(x):
|
||||
a = A(x)
|
||||
t = paddle.to_tensor(x)
|
||||
return t.mean()
|
||||
|
||||
|
||||
class TestInit(TestCaseBase):
|
||||
def test_init_paddle_layer(self):
|
||||
self.assert_results(foo, 1, 2)
|
||||
self.assert_results(foo2, 1, 2)
|
||||
|
||||
def test_init_python_object(self):
|
||||
sot_output = symbolic_translate(bar)([1.0, 2.0])
|
||||
dyn_output = bar([1.0, 2.0])
|
||||
self.assert_nest_match(sot_output, dyn_output)
|
||||
|
||||
def test_error(self):
|
||||
def run():
|
||||
inputs = paddle.randn((10, 10))
|
||||
symbolic_translate(error_foo)(inputs)
|
||||
|
||||
self.assertRaises(paddle.jit.sot.utils.exceptions.InnerError, run)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_created_layer_reconstruct(self):
|
||||
self.assert_results(created_layer_reconstruct)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,89 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import operator
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.opcode_translator.executor.function_graph import (
|
||||
FunctionGraph,
|
||||
)
|
||||
from paddle.jit.sot.opcode_translator.executor.tracker import (
|
||||
DanglingTracker,
|
||||
LocalTracker,
|
||||
)
|
||||
from paddle.jit.sot.opcode_translator.executor.variables import (
|
||||
BuiltinVariable,
|
||||
VariableFactory,
|
||||
)
|
||||
|
||||
|
||||
def compute(x, y):
|
||||
ret = BuiltinVariable(operator.add, x.graph, DanglingTracker())(x, y)
|
||||
return BuiltinVariable(operator.mul, x.graph, DanglingTracker())(ret, x)
|
||||
|
||||
|
||||
def try_add(x, y):
|
||||
return BuiltinVariable(operator.add, x.graph, DanglingTracker())(x, y)
|
||||
|
||||
|
||||
class TestRollback(TestCaseBase):
|
||||
def test_rollback(self):
|
||||
frame = inspect.currentframe()
|
||||
assert frame is not None
|
||||
graph = FunctionGraph(frame.f_code, frame.f_globals)
|
||||
a = paddle.to_tensor(1.0)
|
||||
b = paddle.to_tensor(2.0)
|
||||
a = VariableFactory().from_value(a, graph, LocalTracker("a"))
|
||||
b = VariableFactory().from_value(b, graph, LocalTracker("b"))
|
||||
out = compute(a, b)
|
||||
original_length = len(graph.sir_builder.current_sir.statements)
|
||||
memo = graph.save_memo()
|
||||
try_add(out, out)
|
||||
|
||||
assert len(graph.sir_builder.current_sir.statements) != len(
|
||||
memo.stmt_ir.statements
|
||||
), "After add, we must statement IR."
|
||||
graph.restore_memo(memo)
|
||||
|
||||
assert len(graph.sir_builder.current_sir.statements) == original_length
|
||||
|
||||
|
||||
def fn_with_side_effects_inner(x, y):
|
||||
x[0] += 10
|
||||
x[1] += 20
|
||||
x[2] -= 10
|
||||
print(y) # print will cause breakgraph
|
||||
|
||||
|
||||
def fn_with_side_effects(x, y):
|
||||
x[0] += 1
|
||||
fn_with_side_effects_inner(x, y)
|
||||
return x[0] + y
|
||||
|
||||
|
||||
class TestSideEffectRollback(TestCaseBase):
|
||||
def test_side_effect_rollback(self):
|
||||
self.assert_results_with_side_effects(
|
||||
fn_with_side_effects, [1, 2, 3], paddle.to_tensor(42)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,51 @@
|
||||
# Copyright (c) 2024 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
|
||||
|
||||
from paddle.jit.sot.utils import Cache
|
||||
|
||||
|
||||
class CustomCache(Cache):
|
||||
def key_fn(self, x):
|
||||
return x
|
||||
|
||||
def value_fn(self, x):
|
||||
return x
|
||||
|
||||
|
||||
class TestCache(unittest.TestCase):
|
||||
def test_basic(self):
|
||||
cache = CustomCache()
|
||||
self.assertEqual(cache(1), 1)
|
||||
self.assertEqual(cache(1), 1)
|
||||
|
||||
def test_int_collision(self):
|
||||
cache = CustomCache()
|
||||
# -1 and -2 hash to the same value
|
||||
self.assertEqual(cache(-1), -1)
|
||||
self.assertEqual(cache(-2), -2)
|
||||
|
||||
def test_bool_and_int_collision(self):
|
||||
cache = CustomCache()
|
||||
# 1 and True hash to the same value
|
||||
self.assertEqual(cache(True), True)
|
||||
self.assertEqual(cache(1), 1)
|
||||
# 0 and False hash to the same value
|
||||
self.assertEqual(cache(False), False)
|
||||
self.assertEqual(cache(0), 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,50 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.utils import min_graph_size_guard
|
||||
|
||||
|
||||
def simple_case(x, y):
|
||||
a = x[0]
|
||||
b = x[1]
|
||||
c = paddle.reshape(y, [a, b])
|
||||
# This case use full graph mode, we need to return a list to keep same as SOT
|
||||
return [c]
|
||||
|
||||
|
||||
class TestSotCall(TestCaseBase):
|
||||
@min_graph_size_guard(0)
|
||||
def test_input_with_different_places(self):
|
||||
if paddle.device.is_compiled_with_cuda():
|
||||
a = paddle.to_tensor(
|
||||
[2, 3], dtype='int32', place=paddle.CUDAPlace(0)
|
||||
)
|
||||
b = paddle.ones([3, 2], dtype='int32')
|
||||
_, pp = paddle.jit.to_static(
|
||||
simple_case, full_graph=True
|
||||
).get_concrete_program(a, b)
|
||||
c = paddle.to_tensor([2, 3], dtype='int32', place=paddle.CPUPlace())
|
||||
|
||||
result1 = pp.sot_call([a, b])
|
||||
result2 = pp.sot_call([c, b])
|
||||
self.assert_nest_match(result1, result2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,66 @@
|
||||
# Copyright (c) 2025 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
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
import paddle.distributed as dist
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def fn(x, y):
|
||||
return x + y
|
||||
|
||||
|
||||
@unittest.skipIf(
|
||||
not paddle.is_compiled_with_distribute(),
|
||||
reason='Not compiled with distribute.',
|
||||
)
|
||||
class TestGuardForDistInfo(TestCaseBase):
|
||||
def test_fn(self):
|
||||
x = paddle.ones([2, 2])
|
||||
x.stop_gradient = False
|
||||
y = paddle.zeros([2, 2])
|
||||
y.stop_gradient = False
|
||||
mesh1 = dist.ProcessMesh([0, 1], dim_names=['x'])
|
||||
mesh2 = dist.ProcessMesh([0, 1], dim_names=['y'])
|
||||
mesh3 = dist.ProcessMesh([0, 2], dim_names=['x'])
|
||||
dist_x1 = dist.shard_tensor(
|
||||
x, mesh1, [dist.Replicate()], stop_gradient=False
|
||||
)
|
||||
dist_y1 = dist.shard_tensor(
|
||||
y, mesh1, [dist.Replicate()], stop_gradient=False
|
||||
)
|
||||
dist_x2 = dist.shard_tensor(x, mesh2, [dist.Replicate()])
|
||||
dist_y2 = dist.shard_tensor(y, mesh2, [dist.Replicate()])
|
||||
dist_x3 = dist.shard_tensor(x, mesh3, [dist.Replicate()])
|
||||
dist_y3 = dist.shard_tensor(y, mesh3, [dist.Replicate()])
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
self.assert_results(fn, dist_x1, dist_y1)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(fn, dist_x2, dist_y2)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(fn, dist_x3, dist_y3)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,593 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
from paddle.jit.sot.utils import (
|
||||
ConditionalFallbackError,
|
||||
allow_dynamic_shape_guard,
|
||||
enable_0_size_fallback_guard,
|
||||
specialized_dim_numbers_guard,
|
||||
)
|
||||
|
||||
|
||||
def dynamic_shape_input_func1(x):
|
||||
s = x.shape[0]
|
||||
return x + s
|
||||
|
||||
|
||||
def dynamic_int_input_func1(x, n):
|
||||
x = paddle.reshape(x, [n, -1])
|
||||
return (x + n) * 2 - 1, (-n + 1) * 2 - 1, type(n) is int
|
||||
|
||||
|
||||
def dynamic_shape_with_constraints(x, n):
|
||||
return (x + n) * 2
|
||||
|
||||
|
||||
def dynamic_int_input_func2(x, n):
|
||||
return x + n[1]
|
||||
|
||||
|
||||
def dynamic_int_input_func3(x, n):
|
||||
if n < 4:
|
||||
return 1
|
||||
x = paddle.reshape(x, [n, -1])
|
||||
return (x + n) * 2 - 1, (-n + 1) * 2 - 1
|
||||
|
||||
|
||||
def dynamic_shape_access_inner_var_shape(x):
|
||||
y = x + 1
|
||||
return y.shape[0]
|
||||
|
||||
|
||||
def dynamic_shape_in_list(x, shape):
|
||||
return x.reshape(shape)
|
||||
|
||||
|
||||
def dynamic_shape_int_mul_float(x):
|
||||
y = x * 0.5
|
||||
z = math.sin(y) # Trigger get_py_value
|
||||
return z
|
||||
|
||||
|
||||
def dynamic_shape_constraint(x):
|
||||
s0, s1, *_ = x.shape
|
||||
if s0 < 5:
|
||||
return s0 + x
|
||||
elif s0 < s1:
|
||||
return s0 + x + 1
|
||||
elif 2 * (s0 + s1 - 2) <= 30:
|
||||
return s0 + x + 2
|
||||
else:
|
||||
return s0 + x + 3
|
||||
|
||||
|
||||
class CustomConv(paddle.nn.Conv2D):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@paddle.jit.to_static(full_graph=False)
|
||||
def forward(self, x):
|
||||
return paddle.nn.functional.conv2d(
|
||||
x,
|
||||
self.weight,
|
||||
self.bias,
|
||||
[self._stride[0] + 1, self._stride[1]],
|
||||
self._padding,
|
||||
self._dilation,
|
||||
self._groups,
|
||||
self._data_format,
|
||||
)
|
||||
|
||||
|
||||
def pool2d_fallback(x, kernel_size):
|
||||
return paddle.nn.functional.max_pool2d(x, kernel_size=kernel_size)
|
||||
|
||||
|
||||
class TestOpcodeExecutorDynamicShapeCache(TestCaseBase):
|
||||
def test_dynamic_int_input_cache_hit_case1(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
self.assert_results(
|
||||
dynamic_int_input_func1, paddle.randn([4, 5, 6]), 2
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(3, 7):
|
||||
self.assert_results(
|
||||
dynamic_int_input_func1, paddle.randn([4, 5, 6]), i
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_dynamic_int_input_cache_hit_case2(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
self.assert_results(
|
||||
dynamic_int_input_func2, paddle.randn([4, 5, 6]), {1: 2}
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(3, 7):
|
||||
self.assert_results(
|
||||
dynamic_int_input_func2, paddle.randn([4, 5, 6]), {1: i}
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_dynamic_int_input_cache_hit_case3(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
translate_count_map = {
|
||||
0: 1,
|
||||
1: 2, # 1 is dynamic dim
|
||||
2: 2, # 2 hit cache, no recompile
|
||||
3: 2, # 3 hit cache, no recompile
|
||||
4: 3, # 4 is dynamic dim, but it not hit cache
|
||||
5: 3, # 5 hit cache, no recompile
|
||||
}
|
||||
for i in range(0, 6):
|
||||
self.assert_results(
|
||||
dynamic_int_input_func3, paddle.randn([4, 5, 6]), i
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, translate_count_map[i])
|
||||
|
||||
def test_dynamic_shape_input_cache_hit_case1(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
self.assert_results(
|
||||
dynamic_shape_input_func1, paddle.randn([2, 4, 5])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(3, 7):
|
||||
self.assert_results(
|
||||
dynamic_shape_input_func1, paddle.randn([i, 4, 5])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_dynamic_shape_input_cache_hit_case2(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
self.assert_results(
|
||||
dynamic_shape_access_inner_var_shape, paddle.randn([2, 4, 5])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(3, 7):
|
||||
self.assert_results(
|
||||
dynamic_shape_access_inner_var_shape,
|
||||
paddle.randn([i, 4, 5]),
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_dynamic_shape_cast(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
func1 = check_no_breakgraph(lambda n: bool(n))
|
||||
# TODO(SigureMo): Open these cases
|
||||
# func2 = check_no_breakgraph(lambda n: int(n))
|
||||
# func3 = check_no_breakgraph(lambda n: float(n))
|
||||
for func in [func1]:
|
||||
self.assert_results(func, 1)
|
||||
self.assert_results(func, 2)
|
||||
|
||||
def test_dynamic_shape_in_list(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
self.assert_results(
|
||||
dynamic_shape_in_list,
|
||||
paddle.randn([2, 2, 5]),
|
||||
[4, 5],
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(3, 7):
|
||||
self.assert_results(
|
||||
dynamic_shape_in_list,
|
||||
paddle.randn([i, 2, 5]),
|
||||
[i * 2, 5],
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_conv_dynamic_shape_stride_fallback(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
for i in range(1, 5):
|
||||
conv = CustomConv(3, 3, 3, stride=i)
|
||||
conv(paddle.randn([1, 3, 224, 224]))
|
||||
self.assertEqual(ctx.translate_count, i)
|
||||
|
||||
def test_conv_dynamic_shape_kernel_size_fallback(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
for i in range(1, 5):
|
||||
x = paddle.randn([1, 3, 224, 224])
|
||||
self.assert_results(pool2d_fallback, x, i)
|
||||
self.assertEqual(ctx.translate_count, i)
|
||||
|
||||
def test_pad_dynamic_shape_fallback(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
pad_func = check_no_breakgraph(
|
||||
lambda x, n: paddle.nn.functional.pad(x, [0, n, 0, 0])
|
||||
)
|
||||
for i in range(1, 5):
|
||||
self.assert_results(pad_func, paddle.randn([1, 3, 224, 224]), i)
|
||||
self.assertEqual(ctx.translate_count, 1 if i == 1 else 2)
|
||||
|
||||
def test_dynamic_shape_int_mul_float(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
for i in range(1, 6):
|
||||
self.assert_results(dynamic_shape_int_mul_float, i)
|
||||
|
||||
def test_dynamic_shape_constraint(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
const_dim = 6
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([1, 1, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([2, 2, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2) # add constraint s0 < 5
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([3, 3, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2) # hit constraint s0 < 5
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([4, 4, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2) # hit constraint s0 < 5
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([5, 6, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 3) # add constraint s0 < s1
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([6, 7, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 3) # hit constraint s0 < s1
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([7, 8, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 3) # hit constraint s0 < s1
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([8, 7, const_dim])
|
||||
)
|
||||
self.assertEqual(
|
||||
ctx.translate_count,
|
||||
4, # add constraint 2 * (s0 + s1 - 2) <= 30
|
||||
)
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([9, 8, const_dim])
|
||||
)
|
||||
self.assertEqual(
|
||||
ctx.translate_count,
|
||||
4, # hit constraint 2 * (s0 + s1 - 2) <= 30
|
||||
)
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([10, 9, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 5) # add constraint else
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([11, 10, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 5) # hit constraint else
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([4, 3, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 5) # hit constraint s0 < 5
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([5, 8, const_dim])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 5) # hit constraint s0 < s1
|
||||
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([8, 8, const_dim])
|
||||
)
|
||||
self.assertEqual(
|
||||
ctx.translate_count,
|
||||
5, # hit 2 * (s0 + s1 - 2) <= 30
|
||||
)
|
||||
|
||||
with self.assertRaises(ConditionalFallbackError):
|
||||
self.assert_results(
|
||||
dynamic_shape_constraint, paddle.randn([0, 1, const_dim])
|
||||
)
|
||||
|
||||
def test_mixed_dynamic_and_static(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
a = paddle.randn([4, 5, 6])
|
||||
self.assert_results(dynamic_int_input_func1, a, 1)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(dynamic_int_input_func1, a, 0)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
for i in range(2, 6):
|
||||
self.assert_results(dynamic_int_input_func1, a, i)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
|
||||
def test_mixed_static_after_dynamic(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
a = paddle.randn([4, 5, 6])
|
||||
self.assert_results(dynamic_int_input_func1, a, 2)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(3, 6):
|
||||
self.assert_results(dynamic_int_input_func1, a, i)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
self.assert_results(dynamic_int_input_func1, a, 0)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
self.assert_results(dynamic_int_input_func1, a, 1)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
|
||||
def test_dynamic_shape_with_constraints(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
self.assert_results(
|
||||
dynamic_shape_with_constraints, paddle.randn([4, 5, 6]), 2
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(3, 7):
|
||||
self.assert_results(
|
||||
dynamic_shape_with_constraints,
|
||||
paddle.randn([4 + i, 5, 6]),
|
||||
i,
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dynamic_shape_non_break_non_inplace_ops(x):
|
||||
s0 = x.shape[0]
|
||||
s1 = s0 + 1
|
||||
s2 = 1 + s0
|
||||
s3 = s1 + s2
|
||||
s4 = s1 * s2
|
||||
s5 = s1 - s2
|
||||
s6 = s1 / s2
|
||||
s7 = s1 // s2
|
||||
s8 = s1 % s2
|
||||
s9 = s1**s2
|
||||
s10 = s1 & s2
|
||||
s11 = s1 | s2
|
||||
s12 = s1 ^ s2
|
||||
s13 = s1 << s2
|
||||
s14 = s1 >> s2
|
||||
s15 = s1 == s2
|
||||
s16 = s1 != s2
|
||||
s17 = s1 < s2
|
||||
s18 = s1 <= s2
|
||||
s19 = s1 > s2
|
||||
s20 = s1 >= s2
|
||||
s21 = bool(s1)
|
||||
s22 = not s2
|
||||
return (
|
||||
s0,
|
||||
s1,
|
||||
s2,
|
||||
s3,
|
||||
s4,
|
||||
s5,
|
||||
s6,
|
||||
s7,
|
||||
s8,
|
||||
s9,
|
||||
s10,
|
||||
s11,
|
||||
s12,
|
||||
s13,
|
||||
s14,
|
||||
s15,
|
||||
s16,
|
||||
s17,
|
||||
s18,
|
||||
s19,
|
||||
s20,
|
||||
s21,
|
||||
s22,
|
||||
)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def dynamic_shape_non_break_inplace_ops(x):
|
||||
s0 = x.shape[0]
|
||||
s1 = s0 + 1
|
||||
s2 = s3 = s4 = s5 = s6 = s7 = s8 = s9 = s10 = s11 = s12 = s13 = s0
|
||||
s2 += s1
|
||||
s3 *= s1
|
||||
s4 -= s1
|
||||
# TODO(SigureMo): Open this case, currently the compute result between Python and C++ (Paddle Kernel)
|
||||
# has a small difference (0.8333333134651184 and 0.8333333333333334)
|
||||
# s5 /= s1
|
||||
s6 //= s1
|
||||
s7 %= s1
|
||||
s8 **= s1
|
||||
s9 &= s1
|
||||
s10 |= s1
|
||||
s11 ^= s1
|
||||
s12 <<= s1
|
||||
s13 >>= s1
|
||||
return (
|
||||
s0,
|
||||
s1,
|
||||
s2,
|
||||
s3,
|
||||
s4,
|
||||
# s5,
|
||||
s6,
|
||||
s7,
|
||||
s8,
|
||||
s9,
|
||||
s10,
|
||||
s11,
|
||||
s12,
|
||||
s13,
|
||||
)
|
||||
|
||||
|
||||
class TestDynamicShapeNonBreakOps(TestCaseBase):
|
||||
def test_dynamic_shape_non_break_non_inplace_ops(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
self.assert_results(
|
||||
dynamic_shape_non_break_non_inplace_ops, paddle.randn([4, 5, 6])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(5, 9):
|
||||
self.assert_results(
|
||||
dynamic_shape_non_break_non_inplace_ops,
|
||||
paddle.randn([i, 5, 6]),
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_dynamic_shape_non_break_inplace_ops(self):
|
||||
with (
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
):
|
||||
self.assert_results(
|
||||
dynamic_shape_non_break_inplace_ops, paddle.randn([4, 5, 6])
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
for i in range(5, 9):
|
||||
self.assert_results(
|
||||
dynamic_shape_non_break_inplace_ops,
|
||||
paddle.randn([i, 5, 6]),
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
def dynamic_shape_for_specialized_dim_numbers(x):
|
||||
return x + 1
|
||||
|
||||
|
||||
class TestSpecializedDimNumbers(TestCaseBase):
|
||||
def test_specialized_dim_numbers_01(self):
|
||||
with (
|
||||
specialized_dim_numbers_guard("01"),
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
enable_0_size_fallback_guard(False),
|
||||
):
|
||||
x = paddle.randn([0, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
x = paddle.randn([1, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
x = paddle.randn([2, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
x = paddle.randn([3, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 3)
|
||||
|
||||
def test_specialized_dim_numbers_0(self):
|
||||
with (
|
||||
specialized_dim_numbers_guard("0"),
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
enable_0_size_fallback_guard(False),
|
||||
):
|
||||
x = paddle.randn([0, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
x = paddle.randn([1, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
x = paddle.randn([2, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
x = paddle.randn([3, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_specialized_dim_numbers_no(self):
|
||||
with (
|
||||
specialized_dim_numbers_guard("no"),
|
||||
allow_dynamic_shape_guard(True),
|
||||
test_instruction_translator_cache_context() as ctx,
|
||||
enable_0_size_fallback_guard(False),
|
||||
):
|
||||
x = paddle.randn([10, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
x = paddle.randn([0, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
x = paddle.randn([1, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
x = paddle.randn([2, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
x = paddle.randn([3, 5, 6])
|
||||
self.assert_results(dynamic_shape_for_specialized_dim_numbers, x)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,94 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
|
||||
|
||||
def case1(x):
|
||||
return undefined_var # noqa: F821
|
||||
|
||||
|
||||
def case2(x):
|
||||
x = x + 1
|
||||
return x @ x
|
||||
|
||||
|
||||
def case3(x):
|
||||
y = undefined_var # noqa: F821
|
||||
return y
|
||||
|
||||
|
||||
def case4_inner(x):
|
||||
y = x * 2
|
||||
print()
|
||||
y = y + 1
|
||||
return undefined_var # noqa: F821
|
||||
|
||||
|
||||
def case4(x):
|
||||
return case4_inner(x)
|
||||
|
||||
|
||||
def case5_inner3(x):
|
||||
x += 1
|
||||
print(x)
|
||||
z = x + 1
|
||||
return z
|
||||
|
||||
|
||||
def case5_inner2(x):
|
||||
x += 1
|
||||
z = case5_inner3(y) # noqa: F821
|
||||
return z + 1
|
||||
|
||||
|
||||
def case5_inner1(x):
|
||||
return case5_inner2(x)
|
||||
|
||||
|
||||
def case5(x):
|
||||
y = case5_inner3(x)
|
||||
return case5_inner1(y) + 1
|
||||
|
||||
|
||||
class TestException(unittest.TestCase):
|
||||
def catch_error(self, func, inputs, error_lines: int | list[int]):
|
||||
if isinstance(error_lines, int):
|
||||
error_lines = [error_lines]
|
||||
try:
|
||||
symbolic_translate(func)(inputs)
|
||||
except Exception as e:
|
||||
match_results = re.compile(r'File ".*", line (\d+)').findall(str(e))
|
||||
match_results = list(map(int, match_results))
|
||||
assert match_results == error_lines, (
|
||||
f"{match_results} is not equal {error_lines}"
|
||||
)
|
||||
|
||||
def test_all_case(self):
|
||||
self.catch_error(case1, paddle.rand([2, 1]), 25)
|
||||
# TODO: support runtime error, such as x[111], x@x
|
||||
# self.catch_error(case2, paddle.rand([2, 1]), 30)
|
||||
self.catch_error(case3, paddle.rand([2, 1]), 34)
|
||||
self.catch_error(case4, paddle.rand([2, 1]), 42)
|
||||
self.catch_error(case5, paddle.rand([3, 1]), [68, 63, 58])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,53 @@
|
||||
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.utils import export_guard, min_graph_size_guard
|
||||
|
||||
|
||||
class Net(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.linear = paddle.nn.Linear(2, 2)
|
||||
self.bias = self.create_parameter(
|
||||
shape=[2],
|
||||
attr=None,
|
||||
dtype="float32",
|
||||
is_bias=True,
|
||||
)
|
||||
|
||||
def forward(self, x):
|
||||
a = self.linear(x)
|
||||
return a + self.bias
|
||||
|
||||
|
||||
class TestSotExport(unittest.TestCase):
|
||||
@min_graph_size_guard(0)
|
||||
def test_basic(self):
|
||||
temp_dir = tempfile.TemporaryDirectory()
|
||||
temp_dir_name = temp_dir.name
|
||||
net = Net()
|
||||
x = paddle.to_tensor([2, 3], dtype="float32", stop_gradient=True)
|
||||
with export_guard(temp_dir_name):
|
||||
y = paddle.jit.to_static(net)(x)
|
||||
assert os.path.exists(os.path.join(temp_dir_name, "SIR_0.py"))
|
||||
temp_dir.cleanup()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,208 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_construct_from_list(x: int, y: int):
|
||||
s = paddle.Size([x, y, 3])
|
||||
return s
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_construct_from_tuple(x: int, y: int):
|
||||
s = paddle.Size((x, y, 3))
|
||||
return s
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_getitem_int(x: int, y: int):
|
||||
s = paddle.Size([x, y, 10])
|
||||
return s[1]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_getitem_slice(x: int, y: int):
|
||||
s = paddle.Size([x, y, 10, 20])
|
||||
# Slice of Size should return Size
|
||||
return s[1:3]
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_numel(x: int, y: int):
|
||||
s = paddle.Size([x, y, 2])
|
||||
return s.numel()
|
||||
|
||||
|
||||
# --- Add Operations ---
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_add_list(x: int):
|
||||
s = paddle.Size([x, 2])
|
||||
l = [3, 4]
|
||||
return s + l, l + s
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_add_tuple(x: int):
|
||||
s = paddle.Size([x, 2])
|
||||
t = (3, 4)
|
||||
return s + t, t + s
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_add_size(x: int):
|
||||
s1 = paddle.Size([x, 2])
|
||||
s2 = paddle.Size([3, 4])
|
||||
res = s1 + s2
|
||||
return res
|
||||
|
||||
|
||||
# --- Mul Operations ---
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_mul(x: int):
|
||||
s = paddle.Size([x, 2])
|
||||
res = s * 2
|
||||
return res
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_rmul(x: int):
|
||||
s = paddle.Size([x, 2])
|
||||
res = 2 * s
|
||||
return res
|
||||
|
||||
|
||||
# --- Compare Operations ---
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_compare_tuple(x: int):
|
||||
s = paddle.Size([x, 2])
|
||||
t = (x, 2)
|
||||
t_diff = (x, 3, 4)
|
||||
return (
|
||||
s == t,
|
||||
s == t_diff,
|
||||
s != t,
|
||||
s != t_diff,
|
||||
t == s,
|
||||
t_diff == s,
|
||||
t != s,
|
||||
t_diff != s,
|
||||
)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_compare_list(x: int):
|
||||
s = paddle.Size([x, 2])
|
||||
l = [x, 2]
|
||||
return s == l, s != l, l == s, l != s
|
||||
|
||||
|
||||
# --- Common Methods ---
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_count(x: int):
|
||||
s = paddle.Size([x, x, 2, 3])
|
||||
return s.count(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_index(x: int):
|
||||
s = paddle.Size([2, x, 3])
|
||||
return s.index(x)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_len(x: int):
|
||||
s = paddle.Size([x, x, 2])
|
||||
return len(s)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_iter(x: int):
|
||||
s = paddle.Size([x, 2, 3])
|
||||
res = 0
|
||||
for dim in s:
|
||||
res += dim
|
||||
return res
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def size_contains(x: int):
|
||||
s = paddle.Size([x, 2, 3])
|
||||
return x in s, 99 in s
|
||||
|
||||
|
||||
# --- Symbolic shape---
|
||||
@check_no_breakgraph
|
||||
def symbolic_shape(x: int):
|
||||
s = paddle.zeros(shape=[x, 2, 3])
|
||||
s[0] = 1
|
||||
res = s.unique(return_inverse=False)
|
||||
return res.shape, res.shape.numel()
|
||||
|
||||
|
||||
class TestSizeBasic(TestCaseBase):
|
||||
def test_construct(self):
|
||||
self.assert_results(size_construct_from_list, 1, 2)
|
||||
self.assert_results(size_construct_from_tuple, 1, 2)
|
||||
|
||||
def test_getitem(self):
|
||||
self.assert_results(size_getitem_int, 5, 6)
|
||||
self.assert_results(size_getitem_slice, 5, 6)
|
||||
|
||||
def test_numel(self):
|
||||
self.assert_results(size_numel, 3, 4)
|
||||
self.assert_results(size_numel, 0, 4)
|
||||
|
||||
def test_add(self):
|
||||
self.assert_results(size_add_list, 1)
|
||||
self.assert_results(size_add_tuple, 1)
|
||||
self.assert_results(size_add_size, 1)
|
||||
|
||||
def test_mul(self):
|
||||
self.assert_results(size_mul, 1)
|
||||
self.assert_results(size_rmul, 1)
|
||||
|
||||
def test_compare(self):
|
||||
self.assert_results(size_compare_tuple, 1)
|
||||
self.assert_results(size_compare_list, 1)
|
||||
|
||||
def test_methods(self):
|
||||
self.assert_results(size_count, 1)
|
||||
self.assert_results(size_index, 1)
|
||||
self.assert_results(size_len, 5)
|
||||
self.assert_results(size_iter, 4)
|
||||
self.assert_results(size_contains, 1)
|
||||
|
||||
def test_symbolic_shape(self):
|
||||
self.assert_results(symbolic_shape, 3)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,104 @@
|
||||
# Copyright (c) 2025 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.psdb import check_no_breakgraph
|
||||
|
||||
|
||||
@contextmanager
|
||||
def device_guard(place: str):
|
||||
original_place = paddle.get_device()
|
||||
try:
|
||||
paddle.set_device(place)
|
||||
yield
|
||||
finally:
|
||||
paddle.set_device(original_place)
|
||||
|
||||
|
||||
@check_no_breakgraph
|
||||
def run_diff_logic_by_check_expected_place(x: paddle.Tensor):
|
||||
expected_place_str = paddle.get_device()
|
||||
if "cpu" in expected_place_str:
|
||||
return x + 1
|
||||
elif expected_place_str.startswith("gpu"):
|
||||
return x + 2
|
||||
elif "xpu" in expected_place_str:
|
||||
return x + 3
|
||||
elif "npu" in expected_place_str:
|
||||
return x + 4
|
||||
return x
|
||||
|
||||
|
||||
class TestCheckExpectedPlace(TestCaseBase):
|
||||
def test_check_cpu(self):
|
||||
x = paddle.to_tensor(0.0)
|
||||
with device_guard("cpu"):
|
||||
self.assert_results(run_diff_logic_by_check_expected_place, x.cpu())
|
||||
|
||||
@unittest.skipUnless(
|
||||
paddle.is_compiled_with_cuda(),
|
||||
"This test case needs to be compiled with CUDA",
|
||||
)
|
||||
def test_check_gpu(self):
|
||||
x = paddle.to_tensor(0.0)
|
||||
with device_guard("gpu"):
|
||||
self.assert_results(
|
||||
run_diff_logic_by_check_expected_place, x.cuda()
|
||||
)
|
||||
|
||||
@unittest.skipUnless(
|
||||
paddle.is_compiled_with_xpu(),
|
||||
"This test case needs to be compiled with XPU",
|
||||
)
|
||||
def test_check_xpu(self):
|
||||
x = paddle.to_tensor(0.0)
|
||||
with device_guard("xpu"):
|
||||
self.assert_results(
|
||||
run_diff_logic_by_check_expected_place, x.to("xpu")
|
||||
)
|
||||
|
||||
|
||||
class TestExpectedPlaceGuard(TestCaseBase):
|
||||
@unittest.skipUnless(
|
||||
paddle.is_compiled_with_cuda(),
|
||||
"This test case needs to be compiled with cuda",
|
||||
)
|
||||
def test_expected_place_guard(self):
|
||||
x = paddle.to_tensor(0.0)
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assertEqual(ctx.translate_count, 0)
|
||||
with device_guard("cpu"):
|
||||
self.assert_results(
|
||||
run_diff_logic_by_check_expected_place, x.cpu()
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
with device_guard("gpu"):
|
||||
self.assert_results(
|
||||
run_diff_logic_by_check_expected_place, x.cuda()
|
||||
)
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,59 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.vision.models.resnet import resnet18
|
||||
|
||||
|
||||
def resnet_call(x: paddle.Tensor, net: paddle.nn.Layer):
|
||||
return net(x)
|
||||
|
||||
|
||||
class TestResNet(TestCaseBase):
|
||||
def test_resnet_eval(self):
|
||||
x = paddle.rand((10, 3, 224, 224))
|
||||
net = resnet18(pretrained=False)
|
||||
net.eval()
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(resnet_call, x, net)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(resnet_call, x, net) # cache hit
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
net.train()
|
||||
self.assert_results(resnet_call, x, net) # cache miss
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
def test_resnet_train(self):
|
||||
x = paddle.rand((10, 3, 224, 224))
|
||||
net = resnet18(pretrained=False)
|
||||
net.train()
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
self.assert_results(resnet_call, x, net)
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
self.assert_results(resnet_call, x, net) # cache hit
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
net.eval()
|
||||
self.assert_results(resnet_call, x, net) # cache miss
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,81 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import random
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_equal
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
from paddle.jit.sot.utils.utils import execute_time
|
||||
from paddle.vision import resnet50
|
||||
|
||||
|
||||
def resnet_call(net: paddle.nn.Layer, x: paddle.Tensor):
|
||||
return net(x)
|
||||
|
||||
|
||||
def run_dygraph_optimizer(inp):
|
||||
"""dygraph train + SGD optimizer"""
|
||||
paddle.seed(2021)
|
||||
np.random.seed(2021)
|
||||
random.seed(2021)
|
||||
net = resnet50()
|
||||
optimizer = paddle.optimizer.SGD(
|
||||
learning_rate=0.03, parameters=net.parameters()
|
||||
)
|
||||
for i in range(5):
|
||||
optimizer.clear_grad()
|
||||
loss = execute_time(net)(inp)
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
return loss
|
||||
|
||||
|
||||
def run_symbolic_optimizer(inp):
|
||||
"""dygraph train + SGD optimizer"""
|
||||
paddle.seed(2021)
|
||||
np.random.seed(2021)
|
||||
random.seed(2021)
|
||||
net = resnet50()
|
||||
net_wrapper = symbolic_translate(resnet_call)
|
||||
optimizer = paddle.optimizer.SGD(
|
||||
learning_rate=0.03, parameters=net.parameters()
|
||||
)
|
||||
for i in range(5):
|
||||
optimizer.clear_grad()
|
||||
loss = execute_time(net_wrapper)(net, inp)
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
return loss
|
||||
|
||||
|
||||
class TestBackward(unittest.TestCase):
|
||||
def test(self):
|
||||
# TODO(xiongkun) add cache to speedup !
|
||||
paddle.seed(2021)
|
||||
np.random.seed(2021)
|
||||
random.seed(2021)
|
||||
inp = paddle.rand((3, 3, 255, 255))
|
||||
out2 = run_symbolic_optimizer(inp)[0].numpy()
|
||||
out1 = run_dygraph_optimizer(inp)[0].numpy()
|
||||
assert_array_equal(
|
||||
out1, out2, "Not Equal in dygraph and static graph", True
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,46 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot import symbolic_translate
|
||||
|
||||
|
||||
def api_with_set_stop_gradient(x):
|
||||
y = x + x
|
||||
y.stop_gradient = True
|
||||
return y
|
||||
|
||||
|
||||
class TestApiWithSetStopGradient(unittest.TestCase):
|
||||
def test_api_with_set_stop_gradient(self):
|
||||
x_dy = paddle.to_tensor(1.0, stop_gradient=False)
|
||||
y_dy = api_with_set_stop_gradient(x_dy)
|
||||
y_dy.backward()
|
||||
|
||||
x_st = paddle.to_tensor(1.0, stop_gradient=False)
|
||||
y_st = symbolic_translate(api_with_set_stop_gradient)(x_st)
|
||||
y_st.backward()
|
||||
|
||||
self.assertTrue(y_dy.stop_gradient)
|
||||
self.assertTrue(y_st.stop_gradient)
|
||||
self.assertIsNone(x_dy.grad)
|
||||
self.assertIsNone(x_st.grad)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,42 @@
|
||||
# Copyright (c) 2025 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
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit import sot
|
||||
|
||||
|
||||
class TestArrayWrite(TestCaseBase):
|
||||
def test_array_write(self):
|
||||
def call_array_api():
|
||||
arr = paddle.tensor.create_array(dtype="float32")
|
||||
x = paddle.full(shape=[1, 3], fill_value=5, dtype="float32")
|
||||
i = paddle.zeros(shape=[1], dtype="int32")
|
||||
# The `breakgraph` here is used to document that the `create_array` function has a dynamic-static inconsistency issue.
|
||||
# In SOT, it cannot be directly handled as a PaddleApiVariable; instead, it requires internal function simulation for execution.
|
||||
# Thus, a manual breakpoint is marked to flag this issue.
|
||||
sot.psdb.breakgraph()
|
||||
# The presence of the `item` method within `array_write` / `array_read` can cause breakgraph.
|
||||
arr = paddle.tensor.array_write(x, i, array=arr)
|
||||
item = paddle.tensor.array_read(arr, i)
|
||||
return item
|
||||
|
||||
self.assert_results(call_array_api)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,45 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.opcode_translator.executor.dispatcher import Dispatcher
|
||||
from paddle.jit.sot.utils.envs import min_graph_size_guard
|
||||
|
||||
# 8 will trigger the warmup in RESUME instruction and cause a segmentation fault
|
||||
# RUN_N_TIMES should be larger than 8
|
||||
RUN_N_TIMES = 20
|
||||
|
||||
builtin_fn = str.split
|
||||
# Remove builtin_fn from Dispatcher to ensure that trigger a BreakGraph Error
|
||||
if builtin_fn in Dispatcher.handlers:
|
||||
del Dispatcher.handlers[builtin_fn]
|
||||
|
||||
|
||||
def builtin_fn_with_breakgraph():
|
||||
str.split("1,2,3,4,5", ",")
|
||||
|
||||
|
||||
class TestSpecialization(TestCaseBase):
|
||||
@min_graph_size_guard(10)
|
||||
def test_specialization(self):
|
||||
for _ in range(RUN_N_TIMES):
|
||||
paddle.jit.to_static(builtin_fn_with_breakgraph)()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from paddle.jit.sot.opcode_translator.executor.variable_stack import (
|
||||
VariableStack,
|
||||
)
|
||||
|
||||
|
||||
class TestVariableStack(unittest.TestCase):
|
||||
def test_basic(self):
|
||||
stack = VariableStack([1, 2, 3])
|
||||
self.assertEqual(str(stack), "[1, 2, 3]")
|
||||
self.assertEqual(len(stack), 3)
|
||||
self.assertEqual(str(stack.copy()), str(stack))
|
||||
|
||||
def test_peek(self):
|
||||
stack = VariableStack([1, 2, 3])
|
||||
self.assertEqual(stack.peek(), 3)
|
||||
self.assertEqual(stack.top, 3)
|
||||
self.assertEqual(stack.peek(1), 3)
|
||||
stack.peek[1] = 4
|
||||
stack.peek[2] = 3
|
||||
self.assertEqual(stack.peek[1], 4)
|
||||
self.assertEqual(stack.peek[:1], [4])
|
||||
self.assertEqual(stack.peek[:2], [3, 4])
|
||||
stack.top = 5
|
||||
self.assertEqual(stack.peek[:2], [3, 5])
|
||||
|
||||
def test_push_pop(self):
|
||||
stack = VariableStack()
|
||||
stack.push(1)
|
||||
stack.push(2)
|
||||
self.assertEqual(stack.pop(), 2)
|
||||
self.assertEqual(stack.pop(), 1)
|
||||
|
||||
def test_pop_n(self):
|
||||
stack = VariableStack([1, 2, 3, 4])
|
||||
self.assertEqual(stack.pop_n(2), [3, 4])
|
||||
self.assertEqual(stack.pop_n(2), [1, 2])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,57 @@
|
||||
# Copyright (c) 2024 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.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
import paddle
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
class SimpleModel(paddle.nn.Layer):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.conv1 = paddle.nn.Conv2D(3, 2, 3)
|
||||
self.conv2 = paddle.nn.Conv2D(2, 3, 3)
|
||||
|
||||
def inner_fn(self, x):
|
||||
sot.psdb.fallback()
|
||||
x = self.conv1(x)
|
||||
x = self.conv2(x)
|
||||
return x
|
||||
|
||||
def forward(self, x):
|
||||
x = self.conv1(x)
|
||||
x = self.conv2(x)
|
||||
self.inner_fn(x)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
class TestStepProfilerSmokeTest(unittest.TestCase):
|
||||
# Temporarily disable this test
|
||||
# @sot_step_profiler_guard(True)
|
||||
@strict_mode_guard(False)
|
||||
def test_step_profiler_smoke(self):
|
||||
model = SimpleModel()
|
||||
model = paddle.jit.to_static(model, full_graph=False)
|
||||
x = paddle.randn([1, 3, 32, 32])
|
||||
|
||||
model(x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,37 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
|
||||
# copy from python library _distutils_hack/__init__.py
|
||||
def find_spec(self, fullname, path, target=None):
|
||||
method_name = 'spec_for_{fullname}'.format(
|
||||
**{'self': self, 'fullname': fullname}
|
||||
)
|
||||
method = getattr(self, method_name, lambda: None)
|
||||
return method()
|
||||
|
||||
|
||||
class TestExecutor(TestCaseBase):
|
||||
def test_simple(self):
|
||||
self.assert_results(find_spec, "self", "fullname", "path", None)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2025 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 test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def shape_div(x):
|
||||
return int(np.ceil(x.shape[0] / 7))
|
||||
|
||||
|
||||
class TestSymbolicOperation(TestCaseBase):
|
||||
def test_symbolic_truediv(self):
|
||||
x = paddle.rand([168, 1])
|
||||
paddle.jit.marker.dynamic_dims(x, [0])
|
||||
self.assert_results(shape_div, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,88 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit import sot
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
def foo(x, y):
|
||||
if x.dtype == paddle.float32:
|
||||
out = x + y
|
||||
else:
|
||||
out = x - y
|
||||
return out
|
||||
|
||||
|
||||
def dtype_in_guard(x, y):
|
||||
sot.psdb.fallback()
|
||||
with paddle.amp.auto_cast(level='O2'):
|
||||
for i in range(10):
|
||||
z = foo(x, y)
|
||||
x = z
|
||||
return x
|
||||
|
||||
|
||||
def bar(x, y):
|
||||
if x == paddle.float32:
|
||||
return y + 1
|
||||
else:
|
||||
return y - 1
|
||||
|
||||
|
||||
def dtype_as_input(x, y):
|
||||
sot.psdb.fallback()
|
||||
with paddle.amp.auto_cast(level='O2'):
|
||||
for i in range(10):
|
||||
z = bar(x, y)
|
||||
y = z
|
||||
return y
|
||||
|
||||
|
||||
class TestDtypeInGuard(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_dtype_in_guard(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
x = paddle.to_tensor([2], dtype="float32")
|
||||
y = paddle.to_tensor([3], dtype="float32")
|
||||
self.assert_results(dtype_in_guard, x, y)
|
||||
if sys.version_info >= (3, 11):
|
||||
# skipped with co_exceptiontable flag
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
else:
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
@strict_mode_guard(False)
|
||||
def test_input_dtype_in_guard(self):
|
||||
with test_instruction_translator_cache_context() as ctx:
|
||||
x = paddle.float32
|
||||
y = paddle.to_tensor([3], dtype="float32")
|
||||
self.assert_results(dtype_as_input, x, y)
|
||||
if sys.version_info >= (3, 11):
|
||||
# skipped with co_exceptiontable flag
|
||||
self.assertEqual(ctx.translate_count, 1)
|
||||
else:
|
||||
self.assertEqual(ctx.translate_count, 2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,33 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
|
||||
|
||||
def foo(x: paddle.Tensor):
|
||||
return x[:, 0]
|
||||
|
||||
|
||||
class TestExecutor(TestCaseBase):
|
||||
def test_tensor_slice(self):
|
||||
x = paddle.randn((10, 10))
|
||||
self.assert_results(foo, x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,84 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import (
|
||||
TestCaseBase,
|
||||
test_instruction_translator_cache_context,
|
||||
)
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.utils.envs import allow_dynamic_shape_guard
|
||||
|
||||
|
||||
def foo(x: list[paddle.Tensor], y: list[paddle.Tensor]):
|
||||
return x[0] + y[0]
|
||||
|
||||
|
||||
def bar(x: list[paddle.Tensor], y: int, z: int):
|
||||
return x[y + z] + 1
|
||||
|
||||
|
||||
class TestTraceListArg(TestCaseBase):
|
||||
def test_foo(self):
|
||||
a = paddle.to_tensor(1)
|
||||
b = paddle.to_tensor(2)
|
||||
c = paddle.to_tensor([3, 4])
|
||||
|
||||
with test_instruction_translator_cache_context() as cache:
|
||||
self.assert_results(foo, [a], [b])
|
||||
self.assertEqual(cache.translate_count, 1)
|
||||
self.assert_results(foo, [b], [a]) # Cache hit
|
||||
self.assertEqual(cache.translate_count, 1)
|
||||
self.assert_results(foo, [a], [c]) # Cache miss
|
||||
self.assertEqual(cache.translate_count, 2)
|
||||
|
||||
@allow_dynamic_shape_guard(False)
|
||||
def test_bar_static_shape(self):
|
||||
a = [paddle.to_tensor(1), paddle.to_tensor(2), paddle.to_tensor(3)]
|
||||
b = [paddle.to_tensor([2, 3]), paddle.to_tensor(4), paddle.to_tensor(5)]
|
||||
|
||||
with test_instruction_translator_cache_context() as cache:
|
||||
self.assert_results(bar, a, 1, 1)
|
||||
self.assertEqual(cache.translate_count, 1)
|
||||
self.assert_results(bar, a, 2, 0) # Cache miss
|
||||
self.assertEqual(cache.translate_count, 2)
|
||||
self.assert_results(bar, b, 1, 1) # Cache hit
|
||||
self.assertEqual(cache.translate_count, 2)
|
||||
|
||||
@allow_dynamic_shape_guard(True)
|
||||
def test_bar_dynamic_shape(self):
|
||||
# TODO(zrr1999): mv to dynamic shape test
|
||||
a = [paddle.to_tensor(1), paddle.to_tensor(2), paddle.to_tensor(3)]
|
||||
b = [paddle.to_tensor([2, 3]), paddle.to_tensor(4), paddle.to_tensor(5)]
|
||||
with test_instruction_translator_cache_context() as cache:
|
||||
self.assert_results(bar, a, 1, 1)
|
||||
self.assertEqual(cache.translate_count, 1)
|
||||
self.assert_results(bar, a, 2, 0) # Cache miss
|
||||
self.assertEqual(cache.translate_count, 2)
|
||||
self.assert_results(bar, b, 2, 0) # Cache hit
|
||||
self.assertEqual(cache.translate_count, 3)
|
||||
self.assert_results(bar, b, 2, 0) # Cache hit
|
||||
self.assertEqual(cache.translate_count, 3)
|
||||
self.assert_results(bar, b, 1, 1) # Cache hit
|
||||
self.assertEqual(cache.translate_count, 3)
|
||||
self.assert_results(bar, b, 0, 2) # Cache miss
|
||||
self.assertEqual(cache.translate_count, 4)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,37 @@
|
||||
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
|
||||
from test_case_base import TestCaseBase
|
||||
|
||||
import paddle
|
||||
from paddle.jit.sot.utils import strict_mode_guard
|
||||
|
||||
|
||||
def call_locals(x: int, y: paddle.Tensor):
|
||||
tmp = locals()
|
||||
return x + y + len(list(tmp.keys())), list(tmp.keys())
|
||||
|
||||
|
||||
class TestUnsupportedFunction(TestCaseBase):
|
||||
@strict_mode_guard(False)
|
||||
def test_locals(self):
|
||||
x = paddle.to_tensor([2])
|
||||
y = paddle.to_tensor([3])
|
||||
self.assert_results(call_locals, x, y)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user