Files
paddlepaddle--paddle/test/prim/pir_prim/test_decompose_control_flow.py
T
2026-07-13 12:40:42 +08:00

334 lines
11 KiB
Python

# 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 os
import pathlib
import sys
import unittest
import numpy as np
import paddle
from paddle import base
from paddle.autograd.ir_backward import grad as ir_grad
from paddle.framework import core
sys.path.append(
str(pathlib.Path(__file__).resolve().parents[2] / 'legacy_test')
)
from utils import static_guard
class IfNet(paddle.nn.Layer):
def __init__(self):
super().__init__()
def forward(self, x, y, cond):
if cond:
x = x + 1
out1 = paddle.mean(x)
out2 = paddle.mean(y)
else:
y = y + 1
out1 = paddle.mean(x)
out2 = paddle.mean(y)
return out1, out2
class WhileNet(paddle.nn.Layer):
def __init__(self):
super().__init__()
def forward(self, x, y):
while paddle.all(x < y):
x = x + 1
out = paddle.mean(y**2)
return out
class WhileAndIfNet(paddle.nn.Layer):
def __init__(self):
super().__init__()
def forward(self, x, y):
while paddle.all(x < y):
if paddle.all(x + 1 < y):
x = x + 0.5
out = paddle.mean(y**2)
else:
x = x + 0.6
out = paddle.mean(paddle.nn.functional.softmax(y))
return out
class TestPrimControlFlowIf(unittest.TestCase):
@classmethod
def setUpClass(cls):
core._set_prim_forward_enabled(False)
def setUp(self):
np.random.seed(2023)
self.shape_x = [8, 16, 32]
self.shape_y = [8, 16, 32]
self.x_np = np.random.random(self.shape_x).astype("float32")
self.y_np = np.random.random(self.shape_y).astype("float32")
self.places = []
if (
os.environ.get('FLAGS_CI_both_cpu_and_gpu', 'False').lower()
in ['1', 'true', 'on']
or not paddle.is_compiled_with_cuda()
):
self.places.append(paddle.CPUPlace())
if paddle.is_compiled_with_cuda():
self.places.append(paddle.CUDAPlace(0))
def get_control_if_res(self, x, y, cond, prim_forward=False):
if prim_forward:
core._set_prim_forward_enabled(True)
net = IfNet()
net = paddle.jit.to_static(net, full_graph=True)
out1, out2 = net(x, y, cond)
core._set_prim_forward_enabled(False)
return out1, out2
def test_decompose_if_true(self):
for place in self.places:
if isinstance(place, paddle.base.CPUPlace):
paddle.set_device("cpu")
elif isinstance(place, paddle.base.CUDAPlace):
paddle.set_device("gpu")
x = paddle.to_tensor(self.x_np, dtype="float32")
y = paddle.to_tensor(self.y_np, dtype="float32")
cond = paddle.full(shape=[1], fill_value=1)
out1_baseline, out2_baseline = self.get_control_if_res(
x, y, cond, prim_forward=False
)
out1, out2 = self.get_control_if_res(x, y, cond, prim_forward=True)
np.testing.assert_allclose(out1_baseline, out1, rtol=1e-6, atol=0)
np.testing.assert_allclose(out2_baseline, out2, rtol=1e-6, atol=0)
def test_decompose_if_false(self):
for place in self.places:
if isinstance(place, paddle.base.CPUPlace):
paddle.set_device("cpu")
elif isinstance(place, paddle.base.CUDAPlace):
paddle.set_device("gpu")
x = paddle.to_tensor(self.x_np, dtype="float32")
y = paddle.to_tensor(self.y_np, dtype="float32")
cond = paddle.full(shape=[1], fill_value=0)
out1_baseline, out2_baseline = self.get_control_if_res(
x, y, cond, prim_forward=False
)
out1, out2 = self.get_control_if_res(x, y, cond, prim_forward=True)
np.testing.assert_allclose(out1_baseline, out1, rtol=1e-6, atol=0)
np.testing.assert_allclose(out2_baseline, out2, rtol=1e-6, atol=0)
@classmethod
def tearDownClass(cls):
core._set_prim_forward_enabled(False)
class TestPrimControlFlowWhile(unittest.TestCase):
@classmethod
def setUpClass(cls):
core._set_prim_forward_enabled(False)
def setUp(self):
np.random.seed(2023)
self.shape_x = [8, 16, 32]
self.shape_y = [8, 16, 32]
self.x_np = np.random.random(self.shape_x).astype("float32")
self.y_np = np.random.random(self.shape_y).astype("float32") + 3
self.places = []
if (
os.environ.get('FLAGS_CI_both_cpu_and_gpu', 'False').lower()
in ['1', 'true', 'on']
or not paddle.is_compiled_with_cuda()
):
self.places.append(paddle.CPUPlace())
if paddle.is_compiled_with_cuda():
self.places.append(paddle.CUDAPlace(0))
def get_control_while_res(self, x, y, prim_forward=False):
if prim_forward:
core._set_prim_forward_enabled(True)
net = WhileNet()
net = paddle.jit.to_static(net, full_graph=True)
out = net(x, y)
core._set_prim_forward_enabled(False)
return out
def test_decompose_while(self):
for place in self.places:
if isinstance(place, paddle.base.CPUPlace):
paddle.set_device("cpu")
elif isinstance(place, paddle.base.CUDAPlace):
paddle.set_device("gpu")
x = paddle.to_tensor(self.x_np, dtype="float32")
y = paddle.to_tensor(self.y_np, dtype="float32")
out_baseline = self.get_control_while_res(x, y, prim_forward=False)
out = self.get_control_while_res(x, y, prim_forward=True)
np.testing.assert_allclose(out_baseline, out, rtol=1e-6, atol=0)
@classmethod
def tearDownClass(cls):
core._set_prim_forward_enabled(False)
class TestPrimControlFlowWhileAndIf(unittest.TestCase):
@classmethod
def setUpClass(cls):
core._set_prim_forward_enabled(False)
def setUp(self):
np.random.seed(2023)
self.shape_x = [8, 16, 32]
self.shape_y = [8, 16, 32]
self.x_np = np.random.random(self.shape_x).astype("float32")
self.y_np = np.random.random(self.shape_y).astype("float32") + 3
self.places = []
if (
os.environ.get('FLAGS_CI_both_cpu_and_gpu', 'False').lower()
in ['1', 'true', 'on']
or not paddle.is_compiled_with_cuda()
):
self.places.append(paddle.CPUPlace())
if paddle.is_compiled_with_cuda():
self.places.append(paddle.CUDAPlace(0))
def get_control_flow_res(self, x, y, prim_forward=False):
if prim_forward:
core._set_prim_forward_enabled(True)
net = WhileAndIfNet()
net = paddle.jit.to_static(net, full_graph=True)
out = net(x, y)
core._set_prim_forward_enabled(False)
return out
def test_decompose_while_and_if(self):
for place in self.places:
if isinstance(place, paddle.base.CPUPlace):
paddle.set_device("cpu")
elif isinstance(place, paddle.base.CUDAPlace):
paddle.set_device("gpu")
x = paddle.to_tensor(self.x_np, dtype="float32")
y = paddle.to_tensor(self.y_np, dtype="float32")
out_baseline = self.get_control_flow_res(x, y, prim_forward=False)
out = self.get_control_flow_res(x, y, prim_forward=True)
np.testing.assert_allclose(out_baseline, out, rtol=1e-6, atol=0)
@classmethod
def tearDownClass(cls):
core._set_prim_forward_enabled(False)
class TestPrimControlFlowWhileBackward(unittest.TestCase):
@classmethod
def setUpClass(cls):
core._set_prim_all_enabled(False)
def setUp(self):
np.random.seed(2023)
self.shape_i = [1]
self.shape_x = [1]
self.i_np = np.random.random(self.shape_i).astype("float32")
self.x_np = np.random.random(self.shape_x).astype("float32")
def cond(self, i, x):
return i < 3
def body(self, i, x):
x = paddle.pow(x, i)
i = i + 1
return [i, x]
def get_while_prim_grad_res(self):
core._set_prim_all_enabled(True)
main_program = paddle.static.Program()
startup_program = paddle.static.Program()
with paddle.static.program_guard(main_program, startup_program):
i = paddle.static.data(name='i', shape=[1], dtype='float32')
i.stop_gradient = False
i.persistable = True
x = paddle.static.data(name='x', shape=[1], dtype='float32')
x.stop_gradient = False
x.persistable = True
out = paddle.static.nn.while_loop(self.cond, self.body, [i, x])
[new_out] = paddle.decomposition.decomp.decompose(
main_program, [out[1]]
)
out_grad = ir_grad(new_out, [x])
place = (
base.CUDAPlace(0)
if core.is_compiled_with_cuda()
else base.CPUPlace()
)
exe = base.Executor(place)
out_grad = exe.run(
main_program,
feed={'i': self.i_np, 'x': self.x_np},
fetch_list=[out_grad],
)
core._set_prim_all_enabled(False)
return main_program, out_grad[0]
def get_while_grad_res(self):
core._set_prim_all_enabled(False)
main_program = paddle.static.Program()
startup_program = paddle.static.Program()
with paddle.static.program_guard(main_program, startup_program):
i = paddle.static.data(name='i', shape=[1], dtype='float32')
i.stop_gradient = False
i.persistable = True
x = paddle.static.data(name='x', shape=[1], dtype='float32')
x.stop_gradient = False
x.persistable = True
out = paddle.static.nn.while_loop(self.cond, self.body, [i, x])
out_grad = ir_grad(out, [x])
place = (
base.CUDAPlace(0)
if core.is_compiled_with_cuda()
else base.CPUPlace()
)
exe = base.Executor(place)
out_grad = exe.run(
main_program,
feed={'i': self.i_np, 'x': self.x_np},
fetch_list=[out_grad],
)
return main_program, out_grad[0]
def test_while_loop_backward2(self):
with static_guard():
program_origin, out_grad_baseline = self.get_while_grad_res()
program_prim, out_grad = self.get_while_prim_grad_res()
np.testing.assert_allclose(
out_grad_baseline, out_grad, rtol=1e-6, atol=0
)
assert len(
program_origin.global_block().ops[-1].as_while_op().body().ops
) != len(program_prim.global_block().ops[-1].as_while_op().body().ops)
@classmethod
def tearDownClass(cls):
core._set_prim_all_enabled(False)
if __name__ == "__main__":
unittest.main()