162 lines
5.7 KiB
Python
162 lines
5.7 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 shutil
|
|
import unittest
|
|
|
|
from legacy_test.test_parallel_dygraph_dataparallel import (
|
|
TestMultipleAccelerators,
|
|
)
|
|
|
|
import paddle
|
|
from paddle.distributed.fleet.utils.pp_parallel_adaptor import (
|
|
ParallelConfig,
|
|
PipeLineModelAdaptor,
|
|
adaptor_from_args,
|
|
parse_args,
|
|
)
|
|
|
|
|
|
class TestPPAdaptor(TestMultipleAccelerators):
|
|
def test_parse_args(self):
|
|
args = parse_args()
|
|
self.assertEqual(args.src_mp, args.dst_mp)
|
|
adaptor = adaptor_from_args(args)
|
|
self.assertTrue(adaptor is not None)
|
|
|
|
def test_hybrid_parallel_transformer_unbalanced_data(self):
|
|
print(f"pwd {os.getcwd()}")
|
|
self.run_mnist_2accelerators('hybrid_parallel_pp_transformer_save.py')
|
|
self.run_mnist_2accelerators(
|
|
'hybrid_parallel_pp_transformer_save_with_virtual_stage.py'
|
|
)
|
|
# test pp adaptor
|
|
dir1 = "./pp_transformer"
|
|
p_config1 = ParallelConfig(mp=1, pp=2, vpp=1, sharding=1)
|
|
dir2 = "./pp_transformer_vp"
|
|
p_config2 = ParallelConfig(mp=1, pp=2, vpp=2, sharding=1)
|
|
|
|
pp_to_vp = PipeLineModelAdaptor(
|
|
src_parallel_config=p_config1,
|
|
dst_parallel_config=p_config2,
|
|
transformer_layer_num=8,
|
|
segment_method="layer",
|
|
)
|
|
vp_to_pp = PipeLineModelAdaptor(
|
|
src_parallel_config=p_config2,
|
|
dst_parallel_config=p_config1,
|
|
transformer_layer_num=8,
|
|
segment_method="layer",
|
|
)
|
|
|
|
def check_converted_model(converted_model_dir, expected_model_dir):
|
|
# for compatibility, converted_model_dir may contain more key than
|
|
# expected model, which does not hinder model recovering
|
|
for i in range(p_config1.pp):
|
|
sub_converted_model_dir = (
|
|
f"{converted_model_dir}/mp_00_sharding_00_pp_{i:0>2d}"
|
|
)
|
|
sub_expected_model_dir = (
|
|
f"{expected_model_dir}/mp_00_sharding_00_pp_{i:0>2d}"
|
|
)
|
|
print(
|
|
f"converted_model_dir: {sub_converted_model_dir}; expected_model_dir: {sub_expected_model_dir}"
|
|
)
|
|
|
|
def check_names(dict_1, dict_2):
|
|
for k, v in dict_2.items():
|
|
self.assertTrue(k in dict_1)
|
|
self.assertEqual(
|
|
getattr(v, "name", ""),
|
|
getattr(dict_1[k], "name", ""),
|
|
)
|
|
|
|
# check param
|
|
params_1 = paddle.load(
|
|
f"{sub_converted_model_dir}/model.pdparams"
|
|
)
|
|
params_2 = paddle.load(
|
|
f"{sub_expected_model_dir}/model.pdparams"
|
|
)
|
|
check_names(params_1, params_2)
|
|
del params_1
|
|
del params_2
|
|
# check opt
|
|
opt_1 = paddle.load(
|
|
f"{sub_converted_model_dir}/model_state.pdopt"
|
|
)
|
|
opt_2 = paddle.load(
|
|
f"{sub_expected_model_dir}/model_state.pdopt"
|
|
)
|
|
check_names(opt_1, opt_2)
|
|
# check master weights
|
|
if "master_weights" in opt_2:
|
|
self.assertTrue("master_weights" in opt_1)
|
|
check_names(
|
|
opt_2["master_weights"], opt_1["master_weights"]
|
|
)
|
|
|
|
def create_dir_if_nonexist(dir: str):
|
|
if not os.path.exists(dir):
|
|
os.makedirs(dir)
|
|
|
|
# check pp to vp
|
|
tmp_dir1 = "./tmp_pp_to_vp"
|
|
create_dir_if_nonexist(tmp_dir1)
|
|
pp_to_vp.apply(dir1, tmp_dir1)
|
|
# browse the converted model
|
|
pp_to_vp.peek_model(tmp_dir1)
|
|
# check
|
|
check_converted_model(tmp_dir1, dir2)
|
|
|
|
# check vp to pp
|
|
tmp_dir2 = "./tmp_vp_to_pp"
|
|
create_dir_if_nonexist(tmp_dir2)
|
|
vp_to_pp.apply(dir2, tmp_dir2)
|
|
vp_to_pp.peek_model(tmp_dir2)
|
|
check_converted_model(tmp_dir2, dir1)
|
|
|
|
# check uniform segment
|
|
tmp_dir3 = "./tmp_vp_to_pp_uniform"
|
|
create_dir_if_nonexist(tmp_dir3)
|
|
vp_to_pp_uniform = PipeLineModelAdaptor(
|
|
src_parallel_config=p_config2,
|
|
dst_parallel_config=p_config1,
|
|
transformer_layer_num=8,
|
|
segment_method="uniform",
|
|
)
|
|
vp_to_pp_uniform.apply(dir2, tmp_dir3)
|
|
vp_to_pp_uniform.peek_model(tmp_dir3)
|
|
|
|
tmp_dir4 = "./tmp_pp_to_pp_uniform"
|
|
create_dir_if_nonexist(tmp_dir4)
|
|
pp_to_pp_uniform = PipeLineModelAdaptor(
|
|
src_parallel_config=p_config1,
|
|
dst_parallel_config=p_config1,
|
|
transformer_layer_num=8,
|
|
segment_method="uniform",
|
|
)
|
|
pp_to_pp_uniform.apply(dir1, tmp_dir4)
|
|
pp_to_pp_uniform.peek_model(tmp_dir4)
|
|
check_converted_model(tmp_dir3, tmp_dir4)
|
|
|
|
# rm dirs
|
|
for d in [dir1, dir2, tmp_dir1, tmp_dir2, tmp_dir3, tmp_dir4]:
|
|
shutil.rmtree(d, ignore_errors=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|