From 0b032faeee397b76f1782148a9117e6bca3f60ea Mon Sep 17 00:00:00 2001 From: Chen Weihang Date: Mon, 30 Nov 2020 11:51:15 +0800 Subject: [PATCH] Polish unittests details and execution conditions to adapt to MUSL (#29044) * fix failed tests in yingchun gived list * add unittests into static_mode_white_list * add enable static * fix dist unittest * skip test_sigmoid_focal_loss_op & add gym * revert no need skip unittests * remove gym --- paddle/fluid/framework/CMakeLists.txt | 6 +- .../fluid/tests/unittests/CMakeLists.txt | 53 +++++++++--- .../fluid/tests/unittests/test_desc_clone.py | 31 ------- .../tests/unittests/test_desc_clone_dist.py | 52 +++++++++++ .../test_multiprocess_dataloader_dataset.py | 10 ++- .../tests/unittests/test_program_code.py | 63 +------------- .../tests/unittests/test_program_code_dist.py | 81 ++++++++++++++++++ .../tests/unittests/test_translated_layer.py | 2 +- .../static_mode_white_list.cpython-37.pyc | Bin 0 -> 19830 bytes 9 files changed, 190 insertions(+), 108 deletions(-) create mode 100644 python/paddle/fluid/tests/unittests/test_desc_clone_dist.py create mode 100644 python/paddle/fluid/tests/unittests/test_program_code_dist.py create mode 100644 tools/__pycache__/static_mode_white_list.cpython-37.pyc diff --git a/paddle/fluid/framework/CMakeLists.txt b/paddle/fluid/framework/CMakeLists.txt index 55e56bf2ecc..69978a0b906 100644 --- a/paddle/fluid/framework/CMakeLists.txt +++ b/paddle/fluid/framework/CMakeLists.txt @@ -240,7 +240,8 @@ elseif(WITH_PSLIB) lod_rank_table fs shell fleet_wrapper heter_wrapper box_wrapper lodtensor_printer feed_fetch_method graph_to_program_pass variable_helper timer monitor pslib_brpc ) # TODO: Fix these unittest failed on Windows - if(NOT WIN32) + # This unittest will always failed, now no CI will run this unittest + if(NOT WITH_MUSL AND NOT WIN32) cc_test(test_naive_executor SRCS naive_executor_test.cc DEPS naive_executor elementwise_add_op) endif() else() @@ -254,7 +255,8 @@ else() lod_rank_table fs shell fleet_wrapper heter_wrapper box_wrapper lodtensor_printer feed_fetch_method graph_to_program_pass variable_helper timer monitor) # TODO: Fix these unittest failed on Windows - if(NOT WIN32) + # This unittest will always failed, now no CI will run this unittest + if(NOT WITH_MUSL AND NOT WIN32) cc_test(test_naive_executor SRCS naive_executor_test.cc DEPS naive_executor elementwise_add_op) endif() endif() diff --git a/python/paddle/fluid/tests/unittests/CMakeLists.txt b/python/paddle/fluid/tests/unittests/CMakeLists.txt index b6a99498c7c..1f5c591efc2 100644 --- a/python/paddle/fluid/tests/unittests/CMakeLists.txt +++ b/python/paddle/fluid/tests/unittests/CMakeLists.txt @@ -82,34 +82,58 @@ if(NOT WITH_GPU OR WIN32) endif() if(WIN32) - LIST(REMOVE_ITEM TEST_OPS test_boxps) - LIST(REMOVE_ITEM TEST_OPS test_trainer_desc) LIST(REMOVE_ITEM TEST_OPS test_multiprocess_reader_exception) - LIST(REMOVE_ITEM TEST_OPS test_avoid_twice_initialization) - LIST(REMOVE_ITEM TEST_OPS test_checkpoint_notify_op) +endif() - LIST(REMOVE_ITEM TEST_OPS test_distributed_strategy) +if(WIN32) + LIST(REMOVE_ITEM TEST_OPS test_multiprocess_reader_exception) + LIST(REMOVE_ITEM TEST_OPS test_trainer_desc) + LIST(REMOVE_ITEM TEST_OPS test_checkpoint_notify_op) LIST(REMOVE_ITEM TEST_OPS test_downpoursgd) LIST(REMOVE_ITEM TEST_OPS test_fleet) - LIST(REMOVE_ITEM TEST_OPS test_fleet_metric) LIST(REMOVE_ITEM TEST_OPS test_fleet_nocvm_1) - LIST(REMOVE_ITEM TEST_OPS test_fleet_ps) LIST(REMOVE_ITEM TEST_OPS test_fleet_rolemaker) - LIST(REMOVE_ITEM TEST_OPS test_fleet_rolemaker_2) LIST(REMOVE_ITEM TEST_OPS test_fleet_rolemaker_3) LIST(REMOVE_ITEM TEST_OPS test_fleet_unitaccessor) - LIST(REMOVE_ITEM TEST_OPS test_fleet_utils) - LIST(REMOVE_ITEM TEST_OPS test_lookup_sparse_table_split_op) LIST(REMOVE_ITEM TEST_OPS test_ps_dispatcher) # TODO: Fix these unittests failed on Windows LIST(REMOVE_ITEM TEST_OPS test_debugger) +endif() + +if(NOT WITH_DISTRIBUTE OR WIN32) + # DISTRIBUTE related + LIST(REMOVE_ITEM TEST_OPS test_avoid_twice_initialization) + LIST(REMOVE_ITEM TEST_OPS test_distributed_strategy) + LIST(REMOVE_ITEM TEST_OPS test_fleet_metric) + LIST(REMOVE_ITEM TEST_OPS test_fleet_ps) + LIST(REMOVE_ITEM TEST_OPS test_fleet_rolemaker_2) + LIST(REMOVE_ITEM TEST_OPS test_fleet_utils) + LIST(REMOVE_ITEM TEST_OPS test_lookup_sparse_table_split_op) + + # TODO: Fix these unittests failed on Windows list(REMOVE_ITEM TEST_OPS test_fake_init_op) list(REMOVE_ITEM TEST_OPS test_merge_ids_op) list(REMOVE_ITEM TEST_OPS test_split_ids_op) LIST(REMOVE_ITEM TEST_OPS test_ref_by_trainer_id_op) endif() +if(NOT WITH_DISTRIBUTE) + LIST(REMOVE_ITEM TEST_OPS test_fleet_rolemaker_new) + LIST(REMOVE_ITEM TEST_OPS test_desc_clone_dist) + LIST(REMOVE_ITEM TEST_OPS test_program_code_dist) +endif() + +if(WITH_MUSL) + # TODO: In the musl docker environment provided by SEC, + # the calculation accuracy of testcase in this unittest + # cannot meet the requirement, error like: + # AssertionError: + # 2.3044646853182973e-07 not less than or equal to 1e-07 + # SEC needs to follow up on this issue, and need to be + # resolved before CI requared + LIST(REMOVE_ITEM TEST_OPS test_sigmoid_focal_loss_op) +endif() LIST(REMOVE_ITEM TEST_OPS test_auto_checkpoint) LIST(REMOVE_ITEM TEST_OPS test_auto_checkpoint1) @@ -185,8 +209,12 @@ if(NOT WITH_MKL OR NOT WITH_AVX) list(REMOVE_ITEM TEST_OPS test_match_matrix_tensor_op) list(REMOVE_ITEM TEST_OPS test_var_conv_2d) endif() + if(WITH_COVERAGE OR WIN32 OR WITH_NV_JETSON) list(REMOVE_ITEM TEST_OPS test_pyramid_hash_op) +endif() + +if(NOT WITH_DISTRIBUTE OR WITH_COVERAGE OR WIN32 OR WITH_NV_JETSON) list(REMOVE_ITEM TEST_OPS test_fleet_pyramid_hash) endif() @@ -561,7 +589,7 @@ if(NOT WIN32) set_tests_properties(test_parallel_executor_fetch_feed PROPERTIES TIMEOUT 450) endif() -if(NOT APPLE AND NOT WIN32) +if(WITH_DISTRIBUTE AND NOT APPLE AND NOT WIN32) bash_test_modules(test_auto_checkpoint START_BASH dist_test.sh TIMEOUT 140 LABELS "RUN_TYPE=EXCLUSIVE:NIGHTLY") bash_test_modules(test_auto_checkpoint1 START_BASH dist_test.sh TIMEOUT 140 LABELS "RUN_TYPE=EXCLUSIVE:NIGHTLY") bash_test_modules(test_auto_checkpoint2 START_BASH dist_test.sh TIMEOUT 140 LABELS "RUN_TYPE=EXCLUSIVE:NIGHTLY") @@ -631,6 +659,9 @@ if (NOT WIN32) set_tests_properties(test_multiprocess_reader_exception PROPERTIES TIMEOUT 120) set_tests_properties(test_layers PROPERTIES TIMEOUT 120) set_tests_properties(test_ir_memory_optimize_transformer PROPERTIES TIMEOUT 120) +endif() + +if (WITH_DISTRIBUTE AND NOT WIN32) set_tests_properties(test_fleet_utils PROPERTIES TIMEOUT 120) endif() diff --git a/python/paddle/fluid/tests/unittests/test_desc_clone.py b/python/paddle/fluid/tests/unittests/test_desc_clone.py index 8b1cce5333e..b63c4f55dbc 100644 --- a/python/paddle/fluid/tests/unittests/test_desc_clone.py +++ b/python/paddle/fluid/tests/unittests/test_desc_clone.py @@ -100,16 +100,6 @@ def get_model(batch_size): return inference_program, avg_cost, train_reader, test_reader, batch_acc, predict -def get_transpiler(trainer_id, main_program, pserver_endpoints, trainers): - t = fluid.DistributeTranspiler() - t.transpile( - trainer_id=trainer_id, - program=main_program, - pservers=pserver_endpoints, - trainers=trainers) - return t - - def operator_equal(a, b): if a.__str__() != b.__str__(): raise ValueError("In operator_equal not equal\n") @@ -178,27 +168,6 @@ def program_equal(a, b): return True -class TestDistMnist(unittest.TestCase): - @unittest.skipIf(sys.platform == "win32", - "Windows does not support distribution") - def test_desc_clone(self): - get_model(batch_size=20) - - pserver_endpoints = "127.0.0.1:9123" - trainers = 1 - current_endpoint = "127.0.0.1:9123" - t = get_transpiler(0, - fluid.default_main_program(), pserver_endpoints, - trainers) - - pserver_prog = t.get_pserver_program(current_endpoint) - startup_prog = t.get_startup_program(current_endpoint, pserver_prog) - main = pserver_prog.clone() - startup = startup_prog.clone() - self.assertTrue(program_equal(main, pserver_prog)) - self.assertTrue(program_equal(startup, startup_prog)) - - class TestCloneWithStopGradient(unittest.TestCase): def test_clone_with_stop_gradient(self): train_program = fluid.Program() diff --git a/python/paddle/fluid/tests/unittests/test_desc_clone_dist.py b/python/paddle/fluid/tests/unittests/test_desc_clone_dist.py new file mode 100644 index 00000000000..d342fcce69d --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_desc_clone_dist.py @@ -0,0 +1,52 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +import unittest + +import paddle +import paddle.fluid as fluid + +from test_desc_clone import get_model, program_equal + + +def get_transpiler(trainer_id, main_program, pserver_endpoints, trainers): + t = fluid.DistributeTranspiler() + t.transpile( + trainer_id=trainer_id, + program=main_program, + pservers=pserver_endpoints, + trainers=trainers) + return t + + +class TestDistMnist(unittest.TestCase): + def test_desc_clone(self): + paddle.enable_static() + get_model(batch_size=20) + + pserver_endpoints = "127.0.0.1:9123" + trainers = 1 + current_endpoint = "127.0.0.1:9123" + t = get_transpiler(0, + fluid.default_main_program(), pserver_endpoints, + trainers) + + pserver_prog = t.get_pserver_program(current_endpoint) + startup_prog = t.get_startup_program(current_endpoint, pserver_prog) + main = pserver_prog.clone() + startup = startup_prog.clone() + self.assertTrue(program_equal(main, pserver_prog)) + self.assertTrue(program_equal(startup, startup_prog)) diff --git a/python/paddle/fluid/tests/unittests/test_multiprocess_dataloader_dataset.py b/python/paddle/fluid/tests/unittests/test_multiprocess_dataloader_dataset.py index 496e5320d4c..4ff9b73421a 100644 --- a/python/paddle/fluid/tests/unittests/test_multiprocess_dataloader_dataset.py +++ b/python/paddle/fluid/tests/unittests/test_multiprocess_dataloader_dataset.py @@ -83,7 +83,10 @@ class TestTensorDataset(unittest.TestCase): assert np.allclose(label.numpy(), label_np[i]) def test_main(self): - for p in [fluid.CPUPlace(), fluid.CUDAPlace(0)]: + places = [fluid.CPUPlace()] + if fluid.core.is_compiled_with_cuda(): + places.append(fluid.CUDAPlace(0)) + for p in places: self.run_main(num_workers=0, places=p) @@ -132,7 +135,10 @@ class TestChainDataset(unittest.TestCase): idx += 1 def test_main(self): - for p in [fluid.CPUPlace(), fluid.CUDAPlace(0)]: + places = [fluid.CPUPlace()] + if fluid.core.is_compiled_with_cuda(): + places.append(fluid.CUDAPlace(0)) + for p in places: self.run_main(num_workers=0, places=p) diff --git a/python/paddle/fluid/tests/unittests/test_program_code.py b/python/paddle/fluid/tests/unittests/test_program_code.py index 76ff3f37bf0..e82447519bf 100644 --- a/python/paddle/fluid/tests/unittests/test_program_code.py +++ b/python/paddle/fluid/tests/unittests/test_program_code.py @@ -12,71 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import time -import unittest -import sys -from multiprocessing import Process -import signal +from __future__ import print_function -import numpy +import unittest import paddle.fluid as fluid import paddle.fluid.layers as layers -from paddle.fluid.layers.io import ListenAndServ -from paddle.fluid.layers.io import Recv -from paddle.fluid.layers.io import Send -import paddle.fluid.layers.ops as ops - - -class TestProgram2Code(unittest.TestCase): - @unittest.skipIf(sys.platform == "win32", - "Windows does not support distribution") - def test_print(self): - place = fluid.CPUPlace() - self.init_serv(place) - self.init_client(place, 9123) - - def init_serv(self, place): - main = fluid.Program() - - with fluid.program_guard(main): - serv = ListenAndServ("127.0.0.1:0", ["X"], optimizer_mode=False) - with serv.do(): - out_var = main.global_block().create_var( - name="scale_0.tmp_0", - psersistable=True, - dtype="float32", - shape=[32, 32]) - x = layers.data( - shape=[32, 32], - dtype='float32', - name="X", - append_batch_size=False) - fluid.initializer.Constant(value=1.0)(x, main.global_block()) - ops._scale(x=x, scale=10.0, out=out_var) - - print(main) - - def init_client(self, place, port): - main = fluid.Program() - with fluid.program_guard(main): - x = layers.data( - shape=[32, 32], - dtype='float32', - name='X', - append_batch_size=False) - fluid.initializer.Constant(value=2.3)(x, main.global_block()) - get_var = main.global_block().create_var( - name="scale_0.tmp_0", # server side var - dtype="float32", - persistable=False, - shape=[32, 32]) - fluid.initializer.Constant(value=2.3)(get_var, main.global_block()) - Send("127.0.0.1:%d" % port, [x]) - o = Recv("127.0.0.1:%d" % port, [get_var]) - - print(main) class TestProgramToReadableCode(unittest.TestCase): diff --git a/python/paddle/fluid/tests/unittests/test_program_code_dist.py b/python/paddle/fluid/tests/unittests/test_program_code_dist.py new file mode 100644 index 00000000000..137e490eae8 --- /dev/null +++ b/python/paddle/fluid/tests/unittests/test_program_code_dist.py @@ -0,0 +1,81 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +import unittest +import sys + +import paddle +import paddle.fluid as fluid +import paddle.fluid.layers as layers +from paddle.fluid.layers.io import ListenAndServ +from paddle.fluid.layers.io import Recv +from paddle.fluid.layers.io import Send +import paddle.fluid.layers.ops as ops + + +class TestProgram2Code(unittest.TestCase): + @unittest.skipIf(sys.platform == "win32", + "Windows does not support distribution") + def test_print(self): + paddle.enable_static() + place = fluid.CPUPlace() + self.init_serv(place) + self.init_client(place, 9123) + + def init_serv(self, place): + main = fluid.Program() + + with fluid.program_guard(main): + serv = ListenAndServ("127.0.0.1:0", ["X"], optimizer_mode=False) + with serv.do(): + out_var = main.global_block().create_var( + name="scale_0.tmp_0", + psersistable=True, + dtype="float32", + shape=[32, 32]) + x = layers.data( + shape=[32, 32], + dtype='float32', + name="X", + append_batch_size=False) + fluid.initializer.Constant(value=1.0)(x, main.global_block()) + ops._scale(x=x, scale=10.0, out=out_var) + + print(main) + + def init_client(self, place, port): + main = fluid.Program() + with fluid.program_guard(main): + x = layers.data( + shape=[32, 32], + dtype='float32', + name='X', + append_batch_size=False) + fluid.initializer.Constant(value=2.3)(x, main.global_block()) + get_var = main.global_block().create_var( + name="scale_0.tmp_0", # server side var + dtype="float32", + persistable=False, + shape=[32, 32]) + fluid.initializer.Constant(value=2.3)(get_var, main.global_block()) + Send("127.0.0.1:%d" % port, [x]) + o = Recv("127.0.0.1:%d" % port, [get_var]) + + print(main) + + +if __name__ == "__main__": + unittest.main() diff --git a/python/paddle/fluid/tests/unittests/test_translated_layer.py b/python/paddle/fluid/tests/unittests/test_translated_layer.py index d0b361d6f2c..bf1ed1f06c5 100644 --- a/python/paddle/fluid/tests/unittests/test_translated_layer.py +++ b/python/paddle/fluid/tests/unittests/test_translated_layer.py @@ -94,7 +94,7 @@ class TestTranslatedLayer(unittest.TestCase): batch_size=BATCH_SIZE, shuffle=True, drop_last=True, - num_workers=2) + num_workers=0) # train train(self.layer, self.loader, self.loss_fn, self.sgd) diff --git a/tools/__pycache__/static_mode_white_list.cpython-37.pyc b/tools/__pycache__/static_mode_white_list.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b21e5e7c7401d24358ef5e7853496f6bbc12d057 GIT binary patch literal 19830 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