From 058760b629c5fe1ec071cbfbb7a167228f0353c6 Mon Sep 17 00:00:00 2001 From: ganler Date: Wed, 18 Aug 2021 11:05:54 +0800 Subject: [PATCH 1/3] ToBasicBlockNormalForm immutability --- .../transforms/to_basic_block_normal_form.cc | 11 +++++---- .../test_pass_to_basic_block_normal_form.py | 24 ++++++++++++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/relay/transforms/to_basic_block_normal_form.cc b/src/relay/transforms/to_basic_block_normal_form.cc index 79157bba1918..1ccb981930d6 100644 --- a/src/relay/transforms/to_basic_block_normal_form.cc +++ b/src/relay/transforms/to_basic_block_normal_form.cc @@ -51,8 +51,11 @@ Expr ToBasicBlockNormalFormAux(const Expr& e) { IRModule ToBasicBlockNormalForm(const IRModule& mod) { DLOG(INFO) << "ToBBlock:" << std::endl << mod; + // Efficient copy. + auto mod_ = IRModule(mod->functions, mod->type_definitions, mod->Imports(), mod->source_map); + tvm::Map updates; - auto funcs = mod->functions; + auto funcs = mod_->functions; for (const auto& it : funcs) { ICHECK_EQ(FreeVars(it.second).size(), 0) << "Expected no free variables"; if (const auto* n = it.second.as()) { @@ -63,12 +66,12 @@ IRModule ToBasicBlockNormalForm(const IRModule& mod) { } for (auto pair : updates) { - mod->Add(pair.first, pair.second, true); + mod_->Add(pair.first, pair.second, true); } - DLOG(INFO) << "ToBBlock: transformed" << std::endl << mod; + DLOG(INFO) << "ToBBlock: transformed" << std::endl << mod_; - return mod; + return mod_; } bool BasicBlockNormalFormCheck(const Expr& e) { diff --git a/tests/python/relay/test_pass_to_basic_block_normal_form.py b/tests/python/relay/test_pass_to_basic_block_normal_form.py index d345d465c53e..87afc3b8b5bc 100644 --- a/tests/python/relay/test_pass_to_basic_block_normal_form.py +++ b/tests/python/relay/test_pass_to_basic_block_normal_form.py @@ -22,7 +22,7 @@ from tvm.relay.analysis import detect_feature from tvm.relay import op, create_executor, transform from tvm.relay.prelude import Prelude -from tvm.relay.testing import count +from tvm.relay.testing import count, create_workload from tvm.relay.analysis import Feature from tvm.relay.analysis import check_basic_block_normal_form @@ -489,5 +489,27 @@ def test_higher_order_nested(): check_basic_block_normal_form(bblock) +def test_immutability(): + simple_net = relay.nn.conv2d( + data=relay.var("data", relay.TensorType((1, 3, 224, 224), "float32")), + weight=relay.var("weight"), + kernel_size=(5, 5), + channels=3, + padding=(1, 1), + ) + simple_net = relay.Function(relay.analysis.free_vars(simple_net), simple_net) + mod, _ = create_workload(simple_net) + + old_mod = mod + + with tvm.transform.PassContext(opt_level=4): + with tvm.target.Target("llvm"): + seq = tvm.transform.Sequential(passes=[transform.ToBasicBlockNormalForm()], opt_level=4) + new_mod = seq(mod) + + assert old_mod.astext() == mod.astext() + assert old_mod.astext() != new_mod.astext() + + if __name__ == "__main__": pytest.main([__file__]) From cdaf602680ce9679812378318035c1dda9d92be6 Mon Sep 17 00:00:00 2001 From: ganler Date: Wed, 18 Aug 2021 23:29:09 -0500 Subject: [PATCH 2/3] better comment on ToBasicBlock --- src/relay/transforms/to_basic_block_normal_form.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/relay/transforms/to_basic_block_normal_form.cc b/src/relay/transforms/to_basic_block_normal_form.cc index 1ccb981930d6..628fee8680ca 100644 --- a/src/relay/transforms/to_basic_block_normal_form.cc +++ b/src/relay/transforms/to_basic_block_normal_form.cc @@ -51,7 +51,14 @@ Expr ToBasicBlockNormalFormAux(const Expr& e) { IRModule ToBasicBlockNormalForm(const IRModule& mod) { DLOG(INFO) << "ToBBlock:" << std::endl << mod; - // Efficient copy. + // Use efficient shallow copy here. + // There are typically 4 approaches to "copy" a module: + // 1. `auto mod_ = mod;`: not copy but reference (no new module created); + // 2. `AsText` + `FromText`: copy a module by reload the old one (everything copied); + // 3. `SaveJSON` + `LoadJSON`: same as method 2 but (~40%) faster; + // 4. `auto mod_ = IRModule(...)`: create a new module but share common contents (e.g., functions) + // with the copy-on-write (COW) semantic; it is still a "copy" though + // their contents are usually shared due to COW. auto mod_ = IRModule(mod->functions, mod->type_definitions, mod->Imports(), mod->source_map); tvm::Map updates; From 68a7fe129ea68ab95543f594d08a47c1cb86bfb6 Mon Sep 17 00:00:00 2001 From: ganler Date: Thu, 19 Aug 2021 07:58:33 -0500 Subject: [PATCH 3/3] refine comment of ToBasicBlockForm --- src/relay/transforms/to_basic_block_normal_form.cc | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/relay/transforms/to_basic_block_normal_form.cc b/src/relay/transforms/to_basic_block_normal_form.cc index 628fee8680ca..d03fc1488aea 100644 --- a/src/relay/transforms/to_basic_block_normal_form.cc +++ b/src/relay/transforms/to_basic_block_normal_form.cc @@ -51,14 +51,7 @@ Expr ToBasicBlockNormalFormAux(const Expr& e) { IRModule ToBasicBlockNormalForm(const IRModule& mod) { DLOG(INFO) << "ToBBlock:" << std::endl << mod; - // Use efficient shallow copy here. - // There are typically 4 approaches to "copy" a module: - // 1. `auto mod_ = mod;`: not copy but reference (no new module created); - // 2. `AsText` + `FromText`: copy a module by reload the old one (everything copied); - // 3. `SaveJSON` + `LoadJSON`: same as method 2 but (~40%) faster; - // 4. `auto mod_ = IRModule(...)`: create a new module but share common contents (e.g., functions) - // with the copy-on-write (COW) semantic; it is still a "copy" though - // their contents are usually shared due to COW. + // Create a new module by shallow copy. auto mod_ = IRModule(mod->functions, mod->type_definitions, mod->Imports(), mod->source_map); tvm::Map updates;