chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
file(
GLOB TEST_OPS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"test_*.py")
string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}")
if((NOT WITH_GPU) AND (NOT WITH_XPU))
list(REMOVE_ITEM TEST_OPS "test_dist_fuse_all_reduce_pass")
endif()
if(NOT ((WITH_GPU) AND (CUDA_VERSION GREATER_EQUAL 11.6)))
list(REMOVE_ITEM TEST_OPS test_dist_fuse_gemm_epilogue_pass)
endif()
if(NOT WITH_CUDNN_FRONTEND)
list(REMOVE_ITEM TEST_OPS "test_dist_fuse_resunit_pass")
endif()
foreach(TEST_OP ${TEST_OPS})
py_test_modules(${TEST_OP} MODULES ${TEST_OP} ENVS "NVIDIA_TF32_OVERRIDE=0")
list(APPEND DIST_TEST_OPS ${TEST_OP})
set_tests_properties(${TEST_OP} PROPERTIES TIMEOUT 250)
set_tests_properties(${TEST_OP} PROPERTIES LABELS "RUN_TYPE=DIST")
endforeach()
if(WITH_CUDNN_FRONTEND)
set_tests_properties(test_dist_fuse_resunit_pass PROPERTIES TIMEOUT 350)
endif()
@@ -0,0 +1,47 @@
# Copyright (c) 2021 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 dist_pass_test_base import PassConflictChecker
from model_zoo import resnet_model
from paddle.distributed.passes import new_pass
class CheckPassConflictTest1(PassConflictChecker):
def pass_config(self):
return [
new_pass("fuse_all_reduce", {"max_memory_size": 1024 * 1024}),
new_pass("fuse_elewise_add_act"),
]
def test_resnet(self):
self.check_main(resnet_model, batch_size=32)
class CheckPassConflictTest2(PassConflictChecker):
def pass_config(self):
return [
new_pass("fuse_elewise_add_act"),
new_pass("fuse_all_reduce", {"max_memory_size": 1024 * 1024}),
]
def test_resnet(self):
with self.assertRaises(Exception): # noqa: B017
self.check_main(resnet_model, batch_size=32)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,294 @@
# Copyright (c) 2021 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 os
import pickle
import shlex
import shutil
import sys
import unittest
from collections import OrderedDict
import numpy as np
import paddle
from paddle.distributed.fleet.launch_utils import run_with_coverage
from paddle.distributed.passes.pass_base import PassBase, PassManager
def prepare_python_path_and_return_module(path):
dirname, filename = os.path.split(path)
py_suffix = ".py"
assert filename.endswith(py_suffix), filename
env_name = 'PYTHONPATH'
python_path = os.environ.get(env_name, '')
if python_path:
paths = [p for p in python_path.split(":") if p]
if dirname not in paths:
paths.append(dirname)
python_path = ":".join(paths)
else:
python_path = dirname
os.environ[env_name] = python_path
print('GLOG_v=', os.environ.get('GLOG_v', None), flush=1)
return filename[: -len(py_suffix)]
def remove_path_if_exists(path):
if not os.path.exists(path):
return
if os.path.isfile(path):
os.remove(path)
else:
shutil.rmtree(path)
# NOTE: only support GPU now
class DistPassTestBase(unittest.TestCase):
def setUp(self):
paddle.enable_static()
if paddle.is_compiled_with_cuda():
paddle.set_flags({'FLAGS_cudnn_deterministic': 1})
seed = int(os.environ.get('SEED', -1))
if seed <= 0:
seed = np.random.randint(low=1, high=1000000, size=[1])[0]
os.environ['SEED'] = str(seed)
self.seed = seed
paddle.seed(self.seed)
self.rtol = 1e-5
self.atol = 1e-8
self.equal_nan = False
self.init()
def init(self):
pass
def get_model(self, place, **kwargs):
raise NotImplementedError
def apply_passes(self, main_prog, startup_prog):
raise NotImplementedError
def check_main(self, model=None, gpus=None, **kwargs):
pass_rets = self._distributed_launch(
model=model, apply_pass=True, gpus=gpus, **kwargs
)
no_pass_rets = self._distributed_launch(
model=model, apply_pass=False, gpus=gpus, **kwargs
)
self.check_results(no_pass_rets, pass_rets)
def check_results(self, no_pass_rets, pass_rets):
self.assertEqual(len(no_pass_rets), len(pass_rets))
for no_pass_ret, pass_ret in zip(no_pass_rets, pass_rets):
self.assertEqual(len(no_pass_ret), len(pass_ret))
for i, (out_var_no_pass, out_var_pass) in enumerate(
zip(no_pass_ret, pass_ret)
):
if out_var_no_pass is None:
self.assertIsNone(out_var_pass)
else:
self.assertEqual(len(out_var_pass), len(out_var_no_pass))
for i in range(0, len(out_var_pass)):
np.testing.assert_allclose(
out_var_no_pass[i],
out_var_pass[i],
rtol=self.rtol,
atol=self.atol,
equal_nan=self.equal_nan,
)
@classmethod
def _to_var_names(cls, names_or_vars):
if not isinstance(names_or_vars, (list, tuple)):
names_or_vars = [names_or_vars]
ret_var_names = []
for name_or_var in names_or_vars:
if isinstance(name_or_var, str):
ret_var_names.append(name_or_var)
else:
ret_var_names.append(name_or_var.name)
return ret_var_names
def _run_gpu_main(self, model, apply_pass, dump_file, **kwargs):
gpu_id = int(os.environ.get('FLAGS_selected_gpus', 0))
place = paddle.CUDAPlace(gpu_id)
scope = paddle.static.Scope()
if model is None:
model = self.get_model
with (
paddle.static.program_guard(
paddle.static.Program(), paddle.static.Program()
),
paddle.static.scope_guard(scope),
paddle.base.unique_name.guard(),
):
main_prog, startup_prog, inputs, outputs, reader = model(
place, **kwargs
)
inputs = self._to_var_names(inputs)
outputs = self._to_var_names(outputs)
if apply_pass:
self.apply_passes(main_prog, startup_prog)
all_fetch_values = []
exe = paddle.static.Executor(place)
with paddle.static.scope_guard(scope):
exe.run(startup_prog)
for batch_id, input_data in enumerate(reader()):
assert len(input_data) == len(inputs), (
f"{len(input_data)} vs {len(inputs)}"
)
feed = dict(zip(inputs, input_data))
fetch_values = exe.run(main_prog, feed=feed, fetch_list=outputs)
if paddle.distributed.get_rank() == 0:
output_dict = OrderedDict(zip(outputs, fetch_values))
print(f'batch {batch_id}, outputs {output_dict}')
all_fetch_values.append(fetch_values)
with open(dump_file, "wb") as f:
pickle.dump(all_fetch_values, f)
@classmethod
def _get_default_gpu_lists(cls):
visible_devices = os.getenv("CUDA_VISIBLE_DEVICES")
if visible_devices is None:
visible_devices = os.getenv("FLAGS_selected_gpus")
if visible_devices is None:
num_gpus = paddle.device.cuda.device_count()
return list(range(num_gpus))
else:
return [
int(s.strip()) for s in visible_devices.split(",") if s.strip()
]
def _distributed_launch(self, model, apply_pass, gpus=None, **kwargs):
if gpus is None:
gpus = self._get_default_gpu_lists()
num_gpus = len(gpus)
gpus = ','.join([str(gpu_id) for gpu_id in gpus])
pid = os.getpid()
if apply_pass:
output_dir = f"test_with_pass_{pid}"
else:
output_dir = f"test_without_pass_{pid}"
remove_path_if_exists(output_dir)
os.makedirs(output_dir, mode=0o777)
input_dump_file = os.path.join(output_dir, 'inputs.bin')
model_dump_file = os.path.join(output_dir, 'model.bin')
if os.environ.get("WITH_COVERAGE", "OFF") == "ON":
run_with_coverage(True)
coverage_args = ["-m", "coverage", "run", "--branch", "-p"]
else:
coverage_args = []
file_dir = os.path.dirname(os.path.abspath(__file__))
try:
with open(input_dump_file, 'wb') as f:
pickle.dump(kwargs, f)
if model is not None:
with open(model_dump_file, 'wb') as f:
pickle.dump(model, f)
cmd = [
sys.executable,
"-u",
*coverage_args,
"-m",
"launch",
"--log_dir",
output_dir,
"--gpus",
gpus,
os.path.join(file_dir, "pass_run_main.py"),
"--file_path",
inspect.getfile(type(self)),
"--class_name",
type(self).__name__,
"--input_file",
input_dump_file,
"--output_dir",
output_dir,
]
if apply_pass:
cmd += ["--apply_pass"]
if model is not None:
cmd += ["--model_file", model_dump_file]
cmd = [shlex.quote(c) for c in cmd]
prepare_python_path_and_return_module(__file__)
exitcode = os.system(' '.join(cmd))
self.assertEqual(
exitcode,
0,
f"Pass test failed with apply_pass = {apply_pass}, please view log in {output_dir}",
)
results = []
for i in range(num_gpus):
dump_file = f'{output_dir}/{i}.bin'
self.assertTrue(
os.path.exists(dump_file),
f"Pass test failed with apply_pass = {apply_pass}, please view log in {output_dir}",
)
with open(dump_file, "rb") as f:
results.append(pickle.load(f))
return results
finally:
if int(os.environ.get("DEBUG", 0)) == 0:
remove_path_if_exists(output_dir)
class PassConflictChecker(DistPassTestBase):
def setUp(self):
os.environ['DEBUG'] = '0'
super().setUp()
def pass_config(self):
raise NotImplementedError
def apply_passes(self, main_prog, startup_prog):
passes = self.pass_config()
if not isinstance(passes, (list, tuple)):
passes = [passes]
for p in passes:
self.assertTrue(isinstance(p, PassBase))
auto_pass_manager = PassManager(passes, auto_solve_conflict=True)
new_passes = auto_pass_manager.passes
self.assertEqual(
len(passes),
len(new_passes),
f"After solving conflicts, the left passes are: {auto_pass_manager.names}",
)
for i, (p1, p2) in enumerate(zip(passes, new_passes)):
self.assertEqual(
id(p1),
id(p2),
f"After solving conflicts, the {i}-th pass is different: {p1.name} vs {p2.name}",
)
auto_pass_manager.apply([main_prog], [startup_prog])
+23
View File
@@ -0,0 +1,23 @@
# Copyright (c) 2021 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
from paddle.distributed.fleet import launch
from paddle.distributed.fleet.launch_utils import run_with_coverage
if __name__ == "__main__":
if os.environ.get("WITH_COVERAGE", "OFF") == "ON":
run_with_coverage(True)
launch.launch()
+109
View File
@@ -0,0 +1,109 @@
# Copyright (c) 2021 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 numpy as np
import paddle
from paddle import nn
from paddle.distributed import fleet
from paddle.vision.models import resnet50 as resnet
__all__ = [
'resnet_model',
]
def get_seed_from_env():
return int(os.environ.get("SEED", 0))
def resnet_model(
place, batch_size, image_shape=[3, 224, 224], num_classes=1000
):
image = paddle.static.data(
shape=[batch_size, *image_shape], dtype='float32', name='image'
)
label = paddle.static.data(
shape=[batch_size, 1], dtype='int64', name='label'
)
model = resnet(pretrained=False)
loss_fn = nn.loss.CrossEntropyLoss()
pred_out = model(image)
loss = loss_fn(pred_out, label)
optimizer = paddle.optimizer.Adam(learning_rate=1e-3)
dist_strategy = fleet.DistributedStrategy()
dist_strategy.fuse_all_reduce_ops = False
dist_strategy.without_graph_optimization = True
fleet.init(is_collective=True, strategy=dist_strategy)
optimizer = fleet.distributed_optimizer(optimizer)
optimizer.minimize(loss)
rank = paddle.distributed.get_rank()
def reader():
seed = get_seed_from_env()
np.random.seed(seed + rank)
for _ in range(10):
image_np = np.random.random(size=image.shape).astype('float32')
label_np = np.random.randint(
low=0, high=num_classes, size=label.shape
).astype('int64')
yield image_np, label_np
main_program = paddle.static.default_main_program()
startup_program = paddle.static.default_startup_program()
return main_program, startup_program, [image, label], [loss], reader
def simple_net(place, batch_size, image_shape=[784], num_classes=10):
image = paddle.static.data(
shape=[batch_size, *image_shape], dtype='float32', name='image'
)
label = paddle.static.data(
shape=[batch_size, 1], dtype='int64', name='label'
)
linears = [nn.Linear(784, 784) for _ in range(3)]
hidden = image
for linear in linears:
hidden = linear(hidden)
hidden = nn.ReLU()(hidden)
loss_fn = nn.loss.CrossEntropyLoss()
loss = loss_fn(hidden, label)
optimizer = paddle.optimizer.Adam(learning_rate=1e-3)
dist_strategy = fleet.DistributedStrategy()
dist_strategy.fuse_all_reduce_ops = False
dist_strategy.without_graph_optimization = True
fleet.init(is_collective=True, strategy=dist_strategy)
optimizer = fleet.distributed_optimizer(optimizer)
optimizer.minimize(loss)
rank = paddle.distributed.get_rank()
def reader():
seed = get_seed_from_env()
np.random.seed(seed + rank)
for _ in range(10):
image_np = np.random.random(size=image.shape).astype('float32')
label_np = np.random.randint(
low=0, high=num_classes, size=label.shape
).astype('int64')
yield image_np, label_np
main_program = paddle.static.default_main_program()
startup_program = paddle.static.default_startup_program()
return main_program, startup_program, [image, label], [loss], reader
+93
View File
@@ -0,0 +1,93 @@
# Copyright (c) 2021 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 argparse
import importlib
import os
import pickle
from dist_pass_test_base import (
DistPassTestBase,
prepare_python_path_and_return_module,
)
import paddle
from paddle.distributed.fleet.launch_utils import run_with_coverage
def parse_args():
parser = argparse.ArgumentParser(
description='arguments for distributed pass tests'
)
parser.add_argument('--file_path', type=str, help='The test file path.')
parser.add_argument(
'--class_name',
type=str,
help='The test class name. It is the class name that inherits the DistPassTestBase class.',
)
parser.add_argument(
'--apply_pass',
default=False,
action="store_true",
help='Whether to apply distributed passes.',
)
parser.add_argument(
'--input_file',
type=str,
help='The input file which contains the dumped input arguments.',
)
parser.add_argument(
'--output_dir',
type=str,
help='The output directory to save the logs and output results.',
)
parser.add_argument(
'--model_file',
type=str,
help='The input model file which contains the dumped model function.',
)
return parser.parse_args()
def run_main(args):
if os.environ.get("WITH_COVERAGE", "OFF") == "ON":
run_with_coverage(True)
module_name = prepare_python_path_and_return_module(args.file_path)
test_module = importlib.import_module(module_name)
test_class = getattr(test_module, args.class_name)
assert issubclass(test_class, DistPassTestBase)
test_obj = test_class()
rank = paddle.distributed.get_rank()
with open(args.input_file, "rb") as f:
kwargs = pickle.load(f)
output_file = f"{args.output_dir}/{rank}.bin"
if args.model_file:
with open(args.model_file, "rb") as f:
model = pickle.load(f)
else:
model = None
try:
test_obj.setUpClass()
test_obj.setUp()
test_obj._run_gpu_main(model, args.apply_pass, output_file, **kwargs)
finally:
test_obj.tearDown()
test_obj.tearDownClass()
if __name__ == "__main__":
args = parse_args()
run_main(args)
@@ -0,0 +1,130 @@
# Copyright (c) 2021 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 shlex
import sys
import unittest
from dist_pass_test_base import ( # noqa: F401
prepare_python_path_and_return_module,
remove_path_if_exists,
)
class PsPassTestBase(unittest.TestCase):
def init(self):
self.config = {}
self.config['ps_mode_config'] = ""
self.config['worker_num'] = "1"
self.config['server_num'] = "1"
self.config['run_minimize'] = "0"
self.config['run_single_pass'] = "0"
self.config['run_the_one_ps'] = '0'
self.config['debug_new_minimize'] = "0"
self.config['debug_new_pass'] = "0"
self.config['debug_the_one_ps'] = '0'
self.config['log_dir'] = ""
self.config['applied_pass_name'] = ""
def setUp(self):
print('Ps setUp...')
def tearDown(self):
print('Ps tearDown...')
def ps_launch(self, ps_mode="cpu-ps"):
if ps_mode == "cpu-ps" or ps_mode == 'heter-ps':
os.environ['WITH_DISTRIBUTE'] = 'ON'
cmd = [
sys.executable,
"-u",
"-m",
"launch",
"--log_dir",
self.config['log_dir'],
"--worker_num",
self.config['worker_num'],
"--server_num",
self.config['server_num'],
]
if ps_mode == 'heter-ps':
os.environ['FLAGS_START_PORT'] = '12004'
cmd += [
'--heter_worker_num',
self.config['heter_worker_num'],
'--heter_devices',
self.config['heter_devices'],
]
cmd += [
"../ps/ps_dnn_trainer.py",
"-m",
self.config['ps_mode_config'],
"--run_minimize",
self.config['run_minimize'],
"--run_single_pass",
self.config['run_single_pass'],
"--run_the_one_ps",
self.config['run_the_one_ps'],
"--debug_new_pass",
self.config['debug_new_pass'],
"--debug_new_minimize",
self.config['debug_new_minimize'],
"--applied_pass_name",
self.config['applied_pass_name'],
"--debug_the_one_ps",
self.config['debug_the_one_ps'],
]
elif ps_mode == "gpu-ps":
os.environ['FLAGS_LAUNCH_BARRIER'] = '0'
os.environ['PADDLE_PSERVER_NUMS'] = '1'
os.environ['PADDLE_TRAINERS_NUM'] = '1'
os.environ['POD_IP'] = '127.0.0.1'
os.environ['PADDLE_PSERVERS_IP_PORT_LIST'] = '127.0.0.1:29011'
os.environ['PADDLE_PORT'] = '29011'
os.environ['FLAGS_selected_gpus'] = '0,1,2,3,4,5,6,7'
# pserver
# os.environ['TRAINING_ROLE'] = 'PSERVER'
# trainer
os.environ['TRAINING_ROLE'] = 'TRAINER'
os.environ['PADDLE_TRAINER_ID'] = '0'
cmd = [
sys.executable,
"-u",
"../ps/ps_dnn_trainer.py",
"-m",
self.config['ps_mode_config'],
"--run_minimize",
self.config['run_minimize'],
"--run_single_pass",
self.config['run_single_pass'],
"--run_the_one_ps",
self.config['run_the_one_ps'],
"--debug_new_pass",
self.config['debug_new_pass'],
"--debug_new_minimize",
self.config['debug_new_minimize'],
"--applied_pass_name",
self.config['applied_pass_name'],
"--debug_the_one_ps",
self.config['debug_the_one_ps'],
]
cmd = [shlex.quote(c) for c in cmd]
prepare_python_path_and_return_module(__file__)
exitcode = os.system(' '.join(cmd))
@@ -0,0 +1,39 @@
# Copyright (c) 2022 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 dist_pass_test_base import DistPassTestBase
from paddle.distributed.passes import PassManager, new_pass
class TestBuildCINNPass(DistPassTestBase):
def init(self):
self.atol = 0.5
self.rtol = 0.0
def apply_passes(self, main_prog, startup_prog):
pass_manager = PassManager(
[
new_pass("build_cinn"),
new_pass("fuse_elewise_add_act"),
]
)
pass_manager.apply([main_prog], [startup_prog])
print(pass_manager.names)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,43 @@
# Copyright (c) 2021 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 dist_pass_test_base import DistPassTestBase
from model_zoo import resnet_model
from paddle.distributed.passes import PassManager, new_pass
class TestFuseAllReducePass(DistPassTestBase):
def init(self):
self.atol = 0.0
self.rtol = 0.0
def apply_passes(self, main_prog, startup_prog):
pass_manager = PassManager(
[
new_pass("fuse_elewise_add_act"),
new_pass("fuse_all_reduce", {"max_memory_size": 1024 * 1024}),
]
)
pass_manager.apply([main_prog], [startup_prog])
print(pass_manager.names)
def test_bs_32(self):
self.check_main(resnet_model, batch_size=32)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,210 @@
# Copyright (c) 2022 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 dist_pass_test_base import DistPassTestBase
import paddle
from paddle import nn
from paddle.distributed import fleet
from paddle.distributed.passes import PassManager, new_pass
paddle.enable_static()
np.random.seed(12345)
paddle.seed(12345)
def verify_op_count(op_types, op_name, target_count):
count = 0
for op_type in op_types:
if op_type == op_name:
count += 1
return count == target_count
class MultiFCLayer(nn.Layer):
def __init__(self, hidden, Activation):
super().__init__()
self.linear1 = paddle.nn.Linear(hidden, 4 * hidden)
self.linear2 = paddle.nn.Linear(4 * hidden, hidden)
self.linear3 = paddle.nn.Linear(hidden, hidden)
self.relu1 = Activation()
self.relu2 = Activation()
self.relu3 = Activation()
def forward(self, x, matmul_y, ele_y):
output = self.linear1(x)
output = self.relu1(output)
output = self.linear2(output)
output1 = paddle.matmul(output, matmul_y)
output = self.linear3(output)
output = self.relu2(output)
output = paddle.matmul(output, matmul_y)
output = paddle.add(output, ele_y)
output = self.relu3(output)
output = paddle.add(output, output1)
return output
class TestFuseGemmEpiloguePassReluFP32(DistPassTestBase):
def init(self):
self.atol = 1e-3
self.rtol = 1e-3
self.activation = nn.ReLU
self.act_fwd_name = 'relu'
self.act_bwd_name = 'relu_grad'
self.batch = 64
self.seqlen = 128
self.hidden = 768
self.precision = 'FP32' # FP32 or AMP
def get_model(self, place):
data = paddle.static.data(
name="_data", shape=[-1, self.seqlen, self.hidden], dtype='float32'
)
matmul_y = paddle.static.data(
name="_matmul_y",
shape=[1, self.hidden, self.hidden],
dtype='float32',
)
ele_y = paddle.static.data(
name="_ele_y",
shape=[
self.hidden,
],
dtype='float32',
)
model = MultiFCLayer(self.hidden, self.activation)
out = model(data, matmul_y, ele_y)
loss = paddle.mean(out)
optimizer = paddle.optimizer.Adam(learning_rate=1e-3)
dist_strategy = fleet.DistributedStrategy()
dist_strategy.fuse_all_reduce_ops = False
dist_strategy.without_graph_optimization = True
if self.precision == 'AMP':
dist_strategy.amp = True
dist_strategy.amp_configs = {
"init_loss_scaling": 32768,
"use_dynamic_loss_scaling": True,
"custom_white_list": ['gelu'],
}
fleet.init(is_collective=True, strategy=dist_strategy)
optimizer = fleet.distributed_optimizer(optimizer)
optimizer.minimize(loss)
rank = paddle.distributed.get_rank()
def reader():
for _ in range(10):
data_arr = (
np.random.random(
(self.batch, self.seqlen, self.hidden)
).astype("float32")
- 0.5
)
matmul_y_arr = (
np.random.random((1, self.hidden, self.hidden)).astype(
"float32"
)
- 0.5
)
ele_y_arr = (
np.random.random((self.hidden,)).astype("float32") - 0.5
)
yield [data_arr, matmul_y_arr, ele_y_arr]
main_program = paddle.static.default_main_program()
startup_program = paddle.static.default_startup_program()
fetch_list = []
for p in model.parameters():
grad_name = p.name + '@GRAD'
fetch_list.append(grad_name)
fetch_list.append(loss.name)
return (
main_program,
startup_program,
[data, matmul_y, ele_y],
fetch_list,
reader,
)
def apply_passes(self, main_prog, startup_prog):
pass_manager = PassManager([new_pass("fuse_gemm_epilogue")])
pass_manager.apply([main_prog], [startup_prog])
print(pass_manager.names)
op_type = []
for op in main_prog.global_block().ops:
op_type.append(op.type)
print(op_type)
self.assertTrue(verify_op_count(op_type, "fused_gemm_epilogue", 3))
self.assertTrue(verify_op_count(op_type, "fused_gemm_epilogue_grad", 3))
self.assertTrue(verify_op_count(op_type, self.act_fwd_name, 1))
self.assertTrue(verify_op_count(op_type, self.act_bwd_name, 2))
def test_fuse_gemm_epilogue(self):
self.check_main()
class TestFuseGemmEpiloguePassReluFP16(TestFuseGemmEpiloguePassReluFP32):
def init(self):
self.atol = 1e-3
self.rtol = 1e-3
self.activation = nn.ReLU
self.act_fwd_name = 'relu'
self.act_bwd_name = 'relu_grad'
self.batch = 64
self.seqlen = 128
self.hidden = 768
self.precision = 'AMP' # FP32 or AMP
class TestFuseGemmEpiloguePassGeluFP32(TestFuseGemmEpiloguePassReluFP32):
def init(self):
self.atol = 1e-3
self.rtol = 1e-3
self.activation = nn.GELU
self.act_fwd_name = 'gelu'
self.act_bwd_name = 'gelu_grad'
self.batch = 64
self.seqlen = 128
self.hidden = 768
self.precision = 'FP32' # FP32 or AMP
class TestFuseGemmEpiloguePassGeluFP16(TestFuseGemmEpiloguePassReluFP32):
def init(self):
self.atol = 5e-3
self.rtol = 1e-3
self.activation = nn.GELU
self.act_fwd_name = 'gelu'
self.act_bwd_name = 'gelu_grad'
self.batch = 64
self.seqlen = 128
self.hidden = 768
self.precision = 'AMP' # FP32 or AMP
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,289 @@
# 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 unittest
import numpy as np
from dist_pass_test_base import DistPassTestBase
import paddle
from paddle import ParamAttr, nn
from paddle.distributed import fleet
from paddle.distributed.passes import PassManager, new_pass
from paddle.nn import BatchNorm, Conv2D
from paddle.nn.initializer import Constant, KaimingNormal
paddle.enable_static()
np.random.seed(12345)
paddle.seed(12345)
def skip_unit_test():
return (
not paddle.is_compiled_with_cuda()
or paddle.device.cuda.get_device_capability()[0] < 8
or paddle.get_cudnn_version() < 8900
)
skip_msg = (
"only support with cuda and CUDNN 8.9 or later,"
" and only Ampere or later devices are supported"
)
class ConvBNLayer(nn.Layer):
def __init__(
self,
num_channels,
num_filters,
filter_size,
stride=1,
groups=1,
act=None,
lr_mult=1.0,
data_format="NCHW",
bn_weight_decay=True,
):
super().__init__()
self.act = act
self.conv = Conv2D(
in_channels=num_channels,
out_channels=num_filters,
kernel_size=filter_size,
stride=stride,
padding=(filter_size - 1) // 2,
groups=groups,
weight_attr=ParamAttr(
learning_rate=lr_mult, initializer=KaimingNormal()
),
bias_attr=False,
data_format=data_format,
)
self.bn = BatchNorm(
num_filters,
param_attr=ParamAttr(
learning_rate=lr_mult,
regularizer=(
None if bn_weight_decay else paddle.regularizer.L2Decay(0.0)
),
initializer=Constant(1.0),
),
bias_attr=ParamAttr(
learning_rate=lr_mult,
regularizer=(
None if bn_weight_decay else paddle.regularizer.L2Decay(0.0)
),
initializer=Constant(0.0),
),
data_layout=data_format,
)
self.relu = nn.ReLU()
def forward(self, x):
x = self.conv(x)
x = self.bn(x)
if self.act:
x = self.relu(x)
return x
class BottleneckBlock(nn.Layer):
def __init__(
self,
num_channels,
num_filters,
stride,
shortcut=True,
lr_mult=1.0,
data_format="NCHW",
bn_weight_decay=True,
):
super().__init__()
self.conv0 = ConvBNLayer(
num_channels=num_channels,
num_filters=num_filters,
filter_size=1,
act="relu",
lr_mult=lr_mult,
data_format=data_format,
bn_weight_decay=bn_weight_decay,
)
self.conv1 = ConvBNLayer(
num_channels=num_filters,
num_filters=num_filters,
filter_size=3,
stride=stride,
act="relu",
lr_mult=lr_mult,
data_format=data_format,
bn_weight_decay=bn_weight_decay,
)
self.conv2 = ConvBNLayer(
num_channels=num_filters,
num_filters=num_filters * 4,
filter_size=1,
act=None,
lr_mult=lr_mult,
data_format=data_format,
bn_weight_decay=bn_weight_decay,
)
if not shortcut:
self.short = ConvBNLayer(
num_channels=num_channels,
num_filters=num_filters * 4,
filter_size=1,
stride=stride,
lr_mult=lr_mult,
data_format=data_format,
bn_weight_decay=bn_weight_decay,
)
self.relu = nn.ReLU()
self.shortcut = shortcut
def forward(self, x):
identity = x
x = self.conv0(x)
x = self.conv1(x)
x = self.conv2(x)
if self.shortcut:
short = identity
else:
short = self.short(identity)
x = paddle.add(x=x, y=short)
x = self.relu(x)
return x
class ResUnitNet(nn.Layer):
def __init__(self, shortcut):
super().__init__()
self.shortcut = shortcut
self.conv1 = ConvBNLayer(
num_channels=3,
num_filters=64,
filter_size=3,
act='relu',
data_format='NHWC',
)
self.block = BottleneckBlock(
num_channels=64,
num_filters=16,
stride=1,
shortcut=self.shortcut,
lr_mult=1.0,
data_format="NHWC",
bn_weight_decay=True,
)
self.conv2 = ConvBNLayer(
num_channels=64,
num_filters=64,
filter_size=3,
act='relu',
data_format='NHWC',
)
def forward(self, x):
out = self.conv1(x)
out = self.block(out)
out = self.conv2(out)
out = paddle.flatten(out, 1)
return out
@unittest.skipIf(skip_unit_test(), skip_msg)
class TestFuseResUnitPass(DistPassTestBase):
def init(self):
self.atol = 1e-2
self.rtol = 1e-2
paddle.set_flags({'FLAGS_conv_workspace_size_limit': 1000})
self.init_attr()
def init_attr(self):
self.shortcut = True
def get_model(self, place, batch_size=32, image_shape=[224, 224, 3]):
image = paddle.static.data(
shape=[batch_size, *image_shape], dtype='float32', name='image'
)
model = ResUnitNet(self.shortcut)
pred_out = model(image)
loss = paddle.mean(pred_out)
optimizer = paddle.optimizer.Adam(learning_rate=1e-3)
dist_strategy = fleet.DistributedStrategy()
dist_strategy.fuse_all_reduce_ops = False
dist_strategy.without_graph_optimization = True
dist_strategy.amp = True
dist_strategy.amp_configs = {
"init_loss_scaling": 128.0,
"use_dynamic_loss_scaling": True,
}
build_strategy = paddle.static.BuildStrategy()
settings = {
"fuse_bn_act_ops": False,
"fuse_bn_add_act_ops": False,
"enable_inplace": False,
}
for k, v in settings.items():
setattr(build_strategy, k, v)
dist_strategy.build_strategy = build_strategy
fleet.init(is_collective=True, strategy=dist_strategy)
optimizer = fleet.distributed_optimizer(optimizer)
optimizer.minimize(loss)
rank = paddle.distributed.get_rank()
def reader():
seed = int(os.environ.get("SEED", 0))
np.random.seed(seed + rank)
for _ in range(10):
image_np = np.random.random(size=image.shape).astype('float32')
yield (image_np,)
main_program = paddle.static.default_main_program()
startup_program = paddle.static.default_startup_program()
return main_program, startup_program, [image], [loss], reader
def apply_passes(self, main_prog, startup_prog):
pass_manager = PassManager([new_pass("fuse_resunit")])
pass_manager.apply([main_prog], [startup_prog])
print(pass_manager.names)
op_type = []
for op in main_prog.global_block().ops:
op_type.append(op.type)
self.assertTrue("fused_scale_bias_add_relu" in op_type)
self.assertTrue("fused_scale_bias_relu_conv_bn" in op_type)
self.assertTrue("fused_dconv_drelu_dbn" in op_type)
def test_fuse_resunit(self):
self.check_main()
@unittest.skipIf(skip_unit_test(), skip_msg)
class TestFuseResUnitPassDual(TestFuseResUnitPass):
def init_attr(self):
self.shortcut = False
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,72 @@
# 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 requests
from test_imperative_base import new_program_scope
import paddle
program_txt = '''
{
(%2) = "builtin.parameter" () {parameter_name:"linear_0.w_0",persistable:[true],stop_gradient:[false]} : () -> builtin.tensor<8192x28672xbf16>
(%38) = "pd_op.data" () {dtype:(pd_op.DataType)bfloat16,name:"linear_0.tmp_0",persistable:[false],place:(pd_op.Place)Place(gpu:0),shape:(pd_op.IntArray)[4096,1,28672],stop_gradient:[false]} : () -> builtin.tensor<4096x1x28672xbf16>
(%48) = "pd_op.data" () {dtype:(pd_op.DataType)bfloat16,name:"input",persistable:[false],place:(pd_op.Place)Place(gpu:0),shape:(pd_op.IntArray)[4096,1,28672],stop_gradient:[false]} : () -> builtin.tensor<4096x1x28672xbf16>
(%50) = "pd_op.matmul" (%48, %2) {persistable:[false],stop_gradient:[false],transpose_x:false,transpose_y:true} : (builtin.tensor<4096x1x28672xbf16>, builtin.tensor<8192x28672xbf16>) -> builtin.tensor<4096x1x8192xbf16>
(%57) = "pd_op.all_reduce_" (%50) {event_to_record:"event_7989",events_to_wait:[],execution_stream:"auto_parallel_mp",force_record_event:false,persistable:[false],ring_id:(Int32)36,stop_gradient:[false],reduce_type:(Int32)0,use_model_parallel:true} : (builtin.tensor<4096x1x8192xbf16>) -> builtin.tensor<4096x1x8192xbf16>
(%63) = "pd_op.assign" (%57) {persistable:[false],stop_gradient:[false]} : (builtin.tensor<4096x1x8192xbf16>) -> builtin.tensor<4096x1x8192xbf16>
(%64) = "pd_op.full" () {dtype:(pd_op.DataType)int32,place:(pd_op.Place)Place(cpu),shape:(pd_op.IntArray)[1],stop_gradient:[true],value:(Float)0} : () -> builtin.tensor<1xi32>
(%65) = "pd_op.split_with_num" (%63, %64) {num:(Int32)2,persistable:[false],stop_gradient:[false]} : (builtin.tensor<4096x1x8192xbf16>, builtin.tensor<1xi32>) -> vec[builtin.tensor<2048x1x8192xbf16>,builtin.tensor<2048x1x8192xbf16>]
(%66) = "builtin.slice" (%65) {index:(Int32)0,persistable:[false],stop_gradient:[false]} : (vec[builtin.tensor<2048x1x8192xbf16>,builtin.tensor<2048x1x8192xbf16>]) -> builtin.tensor<2048x1x8192xbf16>
(%67) = "pd_op.assign" (%66) {persistable:[false],stop_gradient:[false]} : (builtin.tensor<2048x1x8192xbf16>) -> builtin.tensor<2048x1x8192xbf16>
}'''
class TestPass(unittest.TestCase):
def test_if_with_single_output(self):
paddle.pir.register_paddle_dialect()
url = "https://paddle-ci.cdn.bcebos.com/json_file/main_program.json"
response = requests.get(url)
response.raise_for_status()
with tempfile.NamedTemporaryFile(delete=False, suffix=".json") as f:
f.write(response.content)
f.flush()
os.fsync(f.fileno())
temp_file_name = f.name
with paddle.pir_utils.IrGuard():
with new_program_scope():
ir_program = paddle.load(temp_file_name)
for op in ir_program.global_block().ops:
if op.name() == 'pd_op.all_reduce_':
op.set_str_attr("event_to_record", "event_7989")
op.set_int_array_attr("events_to_wait", [])
op.set_str_attr("execution_stream", "auto_parallel_mp")
op.set_bool_attr("force_record_event", False)
pm = paddle.pir.PassManager()
pm.add_pass('fuse_allreduce_split_to_reducescatter_pass', {})
pm.run(ir_program)
self.assertEqual(ir_program.global_block().num_ops(), 6)
self.assertEqual(
ir_program.global_block().ops[-2].name(), "pd_op.reduce_scatter"
)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,35 @@
# Copyright (c) 2022 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 ps_pass_test_base import PsPassTestBase
class TestPsServerPass(PsPassTestBase):
def init(self):
pass
def setUp(self):
print('TestPsServerPass setUp...')
def tearDown(self):
print('TestPsServerPass tearDown...')
def test_add_lr_decay_table_pass(self):
pass
if __name__ == '__main__':
unittest.main()
@@ -0,0 +1,97 @@
# Copyright (c) 2021 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.distributed.passes.pass_base import (
PassBase,
_make_rule_from_white_lists_dict as make_white_lists_rule,
new_pass,
register_pass,
)
class TestConcretePass(PassBase):
def __init__(self):
super().__init__()
def _check_self(self):
return True
def _check_conflict(self, other_pass):
return True
def _apply_single_impl(self, main_program, startup_program, context):
pass
@register_pass("A")
class A(TestConcretePass):
def __init__(self):
super().__init__()
@register_pass("B")
class B(TestConcretePass):
def __init__(self):
super().__init__()
@register_pass("C")
class C(TestConcretePass):
def __init__(self):
super().__init__()
@register_pass("D")
class D(TestConcretePass):
def __init__(self):
super().__init__()
@register_pass("E")
class E(TestConcretePass):
def __init__(self):
super().__init__()
class TestMakeWhiteListsRule(unittest.TestCase):
def test_main(self):
before_white_lists = {"A": ["B", "C"]}
after_white_lists = {"D": ["C"]}
rule = make_white_lists_rule(before_white_lists, after_white_lists)
pass_a = new_pass("A")
pass_b = new_pass("B")
pass_c = new_pass("C")
pass_d = new_pass("D")
pass_e = new_pass("E")
self.assertTrue(rule(pass_a, pass_e))
self.assertTrue(rule(pass_e, pass_a))
self.assertTrue(rule(pass_a, pass_b))
self.assertFalse(rule(pass_b, pass_a))
self.assertTrue(rule(pass_a, pass_c))
self.assertFalse(rule(pass_c, pass_a))
self.assertFalse(rule(pass_a, pass_d))
self.assertFalse(rule(pass_d, pass_a))
self.assertTrue(rule(pass_c, pass_d))
self.assertFalse(rule(pass_d, pass_c))
if __name__ == "__main__":
unittest.main()