diff --git a/paddle/fluid/framework/details/build_strategy.h b/paddle/fluid/framework/details/build_strategy.h index be836c380ed7cf5bac6c767a85f280d86abd7631..b06ef5d1d22a7b5e1c393901407f1be805323fc0 100644 --- a/paddle/fluid/framework/details/build_strategy.h +++ b/paddle/fluid/framework/details/build_strategy.h @@ -135,6 +135,7 @@ struct BuildStrategy { bool fuse_adamw_{false}; // Fused feed forward bool fused_feedforward_{false}; + bool force_sequential_run_{false}; // mkldnn_enabled_op_types specify the operator type list to // use MKLDNN acceleration. It is null in default, means @@ -269,6 +270,8 @@ inline std::ostream &operator<<(std::ostream &os, os << "fuse_gemm_epilogue_: " << strategy.fuse_gemm_epilogue_ << std::endl; os << "fused_attention_: " << strategy.fused_attention_ << std::endl; os << "fused_feedforward_: " << strategy.fused_feedforward_ << std::endl; + os << "force_sequential_run_: " << strategy.force_sequential_run_ + << std::endl; os << "mkldnn_enabled_op_types_: "; for (auto str : strategy.mkldnn_enabled_op_types_) { os << str << ", "; diff --git a/paddle/fluid/pybind/parallel_executor.cc b/paddle/fluid/pybind/parallel_executor.cc index 1dc17201f19f09828128bf1ff9cec5bae91722e5..0dc171aabc740e8e5286ac83070faa7c4dfc5d98 100644 --- a/paddle/fluid/pybind/parallel_executor.cc +++ b/paddle/fluid/pybind/parallel_executor.cc @@ -760,6 +760,31 @@ void BindParallelExecutor(pybind11::module &m) { // NOLINT build_strategy.fused_feedforward = True )DOC") .def_property( + "force_sequential_run", + [](const BuildStrategy &self) { return self.force_sequential_run_; }, + [](BuildStrategy &self, bool b) { + PADDLE_ENFORCE_NE(self.IsFinalized(), + true, + platform::errors::PreconditionNotMet( + "BuildStrategy has been finlaized, cannot be " + "configured again.")); + self.force_sequential_run_ = b; + }, + R"DOC((bool, optional): force_sequential_run is used to let the `StandaloneExecutor` run ops by the + order of `ProgramDesc`. Default is False. + + Examples: + .. code-block:: python + + import paddle + import paddle.static as static + + paddle.enable_static() + + build_strategy = static.BuildStrategy() + build_strategy.fused_feedforward = True + )DOC") + .def_property( "fuse_bn_act_ops", [](const BuildStrategy &self) { return self.fuse_bn_act_ops_; }, [](BuildStrategy &self, bool b) { diff --git a/python/paddle/fluid/executor.py b/python/paddle/fluid/executor.py index 2b8b4fcd380e05c806d5bd73527e20dda825415c..55dac9695cdffb4e0aece1f93b1e9fc94a6a9845 100755 --- a/python/paddle/fluid/executor.py +++ b/python/paddle/fluid/executor.py @@ -1609,6 +1609,32 @@ class Executor: ) feed = self._update_feed(program, feed) + stored_flag = {} + if isinstance(program, compiler.CompiledProgram) or isinstance( + program._graph, compiler.CompiledProgram + ): + compiled_program = ( + program + if isinstance(program, compiler.CompiledProgram) + else program._graph + ) + build_strategy = compiled_program._build_strategy + if ( + build_strategy is not None + and build_strategy.force_sequential_run + ): + schedule_flag = [ + 'FLAGS_new_executor_serial_run', + 'FLAGS_new_executor_sequential_run', + ] + for flag in schedule_flag: + value = os.getenv(flag, False) + if isinstance(value, str): + value = value.lower() + value = True if value == 'true' else False + stored_flag[flag] = bool(value) + set_flags({f: True for f in schedule_flag}) + program, new_exe = self._executor_cache.get_program_and_executor( program, feed, @@ -1644,9 +1670,11 @@ class Executor: else: tensor._copy_from(cpu_tensor, self.place) - return new_exe.run( + ret = new_exe.run( scope, list(feed.keys()), fetch_list, return_numpy ) + set_flags(stored_flag) + return ret compiled = isinstance(program, compiler.CompiledProgram) diff --git a/test/standalone_executor/test_standalone_sequentail_run.py b/test/standalone_executor/test_standalone_sequentail_run.py new file mode 100644 index 0000000000000000000000000000000000000000..bc7368e58b4e720510f3117be7aa5e2bd0bc5d91 --- /dev/null +++ b/test/standalone_executor/test_standalone_sequentail_run.py @@ -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 + +import numpy as np + +import paddle + + +class TestStandaloneExecutor(unittest.TestCase): + def build_program(self): + main_program = paddle.static.Program() + startup_program = paddle.static.Program() + with paddle.static.program_guard(main_program, startup_program): + a = paddle.static.data(name="data", shape=[2, 2], dtype='float32') + b = paddle.ones([2, 2]) * 2 + t = paddle.static.nn.fc(a, 2) + c = t + b + + return main_program, startup_program, [c] + + def run_program(self, force_sequential_run=False): + seed = 100 + paddle.seed(seed) + np.random.seed(seed) + main, startup, outs = self.build_program() + build_strategy = paddle.static.BuildStrategy() + build_strategy.force_sequential_run = force_sequential_run + compiled_program = paddle.static.CompiledProgram( + main, build_strategy=build_strategy + ) + + exe = paddle.static.Executor() + scope = paddle.static.Scope() + with paddle.static.scope_guard(scope): + exe.run(startup) + data = np.ones([2, 2], dtype="float32") + ret = exe.run( + compiled_program, + feed={"data": data}, + fetch_list=[v.name for v in outs], + ) + return ret + + def test_result(self): + paddle.enable_static() + ret1 = self.run_program(True) + ret2 = self.run_program(False) + np.testing.assert_array_equal(ret1, ret2) + + +if __name__ == "__main__": + unittest.main()