Skip to content

Commit 0cb6337

Browse files
authored
[TVMC][Relay] Introduce executor and runtime parameters (#9352)
* [TVMC][Relay] Introduce executor and runtime parameters This introduces `executor` and `runtime` into the various entrypoints but also into `tvmc` as `--executor` and `--runtime`. This touchs a lot of files and I've tried to update anywhere as necessary. Notable, executor code generators now accept the initial `IRModule` rather than creating it themselves so it can be annotated once. Validated the demo application continues to classify the tabby cat with new CLI options. * Correct Graph Executor Python API
1 parent 3f5dca5 commit 0cb6337

File tree

72 files changed

+1049
-473
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+1049
-473
lines changed

apps/bundle_deploy/build_model.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@
2020
import os
2121
from tvm import relay
2222
import tvm
23-
from tvm import te, runtime
23+
from tvm import runtime as tvm_runtime
2424
import logging
25-
import json
25+
from tvm.relay.backend import Runtime
2626
from tvm.contrib import cc as _cc
2727

28-
RUNTIMES = {
29-
"c": "{name}_c.{ext}",
30-
"c++": "{name}_cpp.{ext}",
31-
}
28+
RUNTIMES = [
29+
(Runtime("crt", {"system-lib": True}), "{name}_c.{ext}"),
30+
(Runtime("cpp", {"system-lib": True}), "{name}_cpp.{ext}"),
31+
]
3232

3333

3434
def build_module(opts):
@@ -43,18 +43,16 @@ def build_module(opts):
4343
func.params, relay.nn.softmax(func.body), None, func.type_params, func.attrs
4444
)
4545

46-
for runtime_name, file_format_str in RUNTIMES.items():
46+
for runtime, file_format_str in RUNTIMES:
4747
with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}):
48-
graph, lib, params = relay.build(
49-
func, f"llvm --runtime={runtime_name} --system-lib", params=params
50-
)
48+
graph, lib, params = relay.build(func, "llvm", runtime=runtime, params=params)
5149

5250
build_dir = os.path.abspath(opts.out_dir)
5351
if not os.path.isdir(build_dir):
5452
os.makedirs(build_dir)
55-
ext = "tar" if runtime_name == "c" else "o"
53+
ext = "tar" if str(runtime) == "crt" else "o"
5654
lib_file_name = os.path.join(build_dir, file_format_str.format(name="model", ext=ext))
57-
if runtime_name == "c":
55+
if str(runtime) == "crt":
5856
lib.export_library(lib_file_name)
5957
else:
6058
# NOTE: at present, export_libarary will always create _another_ shared object, and you
@@ -70,7 +68,7 @@ def build_module(opts):
7068
with open(
7169
os.path.join(build_dir, file_format_str.format(name="params", ext="bin")), "wb"
7270
) as f_params:
73-
f_params.write(runtime.save_param_dict(params))
71+
f_params.write(tvm_runtime.save_param_dict(params))
7472

7573

7674
def build_test_module(opts):
@@ -84,20 +82,21 @@ def build_test_module(opts):
8482
y_data = np.random.rand(1, 5).astype("float32")
8583
params = {"y": y_data}
8684

87-
for runtime_name, file_format_str in RUNTIMES.items():
85+
for runtime, file_format_str in RUNTIMES:
8886
with tvm.transform.PassContext(opt_level=3, config={"tir.disable_vectorize": True}):
8987
graph, lib, lowered_params = relay.build(
9088
tvm.IRModule.from_expr(func),
91-
f"llvm --runtime={runtime_name} --system-lib",
89+
"llvm",
90+
runtime=runtime,
9291
params=params,
9392
)
9493

9594
build_dir = os.path.abspath(opts.out_dir)
9695
if not os.path.isdir(build_dir):
9796
os.makedirs(build_dir)
98-
ext = "tar" if runtime_name == "c" else "o"
97+
ext = "tar" if str(runtime) == "crt" else "o"
9998
lib_file_name = os.path.join(build_dir, file_format_str.format(name="test_model", ext=ext))
100-
if runtime_name == "c":
99+
if str(runtime) == "crt":
101100
lib.export_library(lib_file_name)
102101
else:
103102
# NOTE: at present, export_libarary will always create _another_ shared object, and you
@@ -113,7 +112,7 @@ def build_test_module(opts):
113112
with open(
114113
os.path.join(build_dir, file_format_str.format(name="test_params", ext="bin")), "wb"
115114
) as f_params:
116-
f_params.write(runtime.save_param_dict(lowered_params))
115+
f_params.write(tvm_runtime.save_param_dict(lowered_params))
117116
with open(
118117
os.path.join(build_dir, file_format_str.format(name="test_data", ext="bin")), "wb"
119118
) as fp:

apps/microtvm/ethosu/run_demo.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,12 @@ curl --retry 64 -sSL ${mobilenet_url} | gunzip | tar -xvf - ./mobilenet_v1_1.0_2
130130
# Compile model for Arm(R) Cortex(R)-M55 CPU and Ethos(TM)-U55 NPU
131131
# An alternative to using "python3 -m tvm.driver.tvmc" is to call
132132
# "tvmc" directly once TVM has been pip installed.
133-
python3 -m tvm.driver.tvmc compile --target="ethos-u -accelerator_config=ethos-u55-256, \
134-
c -runtime=c --link-params -mcpu=cortex-m55 -executor=aot -interface-api=c -unpacked-api=1" \
133+
python3 -m tvm.driver.tvmc compile --target="ethos-u -accelerator_config=ethos-u55-256, c" \
134+
--target-c-mcpu=cortex-m55 \
135+
--runtime=crt \
136+
--executor=aot \
137+
--executor-aot-interface-api=c \
138+
--executor-aot-unpacked-api=1 \
135139
--pass-config tir.disable_vectorize=1 ./mobilenet_v1_1.0_224_quant.tflite --output-format=mlf
136140
tar -xvf module.tar
137141

docs/arch/microtvm_design.rst

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,18 +127,24 @@ logs use it to rank measured performance (but see Future Work).
127127
Targets are currently represented as strings structured similarly to command-line arguments. An
128128
example target is shown below:
129129

130-
``c -keys=arm_cpu -mcpu=cortex-m7 -link-params -model=stm32f746xx -runtime=c -system-lib=1``
130+
``c -keys=arm_cpu -mcpu=cortex-m7 -model=stm32f746xx``
131131

132132
The relevant parts to microTVM are:
133133

134134
* Code generator (``llvm`` or ``c``)
135135
* ``-mcpu=cortex-m7``: used by TOPI to enable Cortex-M schedules, and, when the C source code
136136
generator is selected, included in the output as a comment to help identify the code and
137137
configure the downstream C compiler.
138-
* ``-link-params``: include parameters as global constants to load from flash.
139-
* ``-runtime=c``: build glue code to allow operators to work with the C runtime
140-
* ``-system-lib=1``: emit a system library (i.e. which can be loaded by calling the PackedFunc
141-
``runtime.SystemLib``.
138+
139+
Runtime and Executor configuration for microTVM
140+
-----------------------------------------------
141+
142+
When using microTVM, it's important to use the C Runtime (``Runtime('crt')``), which is the runtime that works best on micro devices rather than the more dynamic C++ Runtime. Alongside this, there are two executors which you could use in combination with the C runtime:
143+
144+
* ``Executor("aot")`` - The Ahead of Time (AOT) executor precompiles the network into a runnable function which you can add directly into your micro application
145+
* ``Executor("graph", {"link-params": True})`` - The Graph executor provides a JSON representation of your network and requires the C Runtime's system library to be generated to find functions in the function registry (``Runtime("crt", {"system-lib": True})``). ``{"link-params":True}`` enables parameters to be linked into the generated files rather than provided externally.
146+
147+
These are specified when building a runtime module: ``relay.build(..., runtime=..., executor=...)``.
142148

143149
Writing Schedules for microTVM
144150
------------------------------

gallery/how_to/work_with_microtvm/micro_autotune.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import pathlib
3333

3434
import tvm
35+
from tvm.relay.backend import Executor, Runtime
3536

3637
####################
3738
# Defining the model
@@ -69,13 +70,15 @@
6970
# Defining the target #
7071
#######################
7172
# Now we define the TVM target that describes the execution environment. This looks very similar
72-
# to target definitions from other microTVM tutorials.
73+
# to target definitions from other microTVM tutorials. Alongside this we pick the C Runtime to code
74+
# generate our model against.
7375
#
7476
# When running on physical hardware, choose a target and a board that
7577
# describe the hardware. There are multiple hardware targets that could be selected from
7678
# PLATFORM list in this tutorial. You can chose the platform by passing --platform argument when running
7779
# this tutorial.
7880
#
81+
RUNTIME = Runtime("crt", {"system-lib": True})
7982
TARGET = tvm.target.target.micro("host")
8083

8184
# Compiling for physical hardware
@@ -123,6 +126,7 @@
123126
build_kwargs={"build_option": {"tir.disable_vectorize": True}},
124127
do_fork=True,
125128
build_func=tvm.micro.autotvm_build_func,
129+
runtime=RUNTIME,
126130
)
127131
runner = tvm.autotvm.LocalRunner(number=1, repeat=1, timeout=100, module_loader=module_loader)
128132

@@ -175,7 +179,7 @@
175179
# the tuned operator.
176180

177181
with pass_context:
178-
lowered = tvm.relay.build(relay_mod, target=TARGET, params=params)
182+
lowered = tvm.relay.build(relay_mod, target=TARGET, runtime=RUNTIME, params=params)
179183

180184
temp_dir = tvm.contrib.utils.tempdir()
181185

@@ -218,7 +222,7 @@
218222

219223
with tvm.autotvm.apply_history_best("microtvm_autotune.log.txt"):
220224
with pass_context:
221-
lowered_tuned = tvm.relay.build(relay_mod, target=TARGET, params=params)
225+
lowered_tuned = tvm.relay.build(relay_mod, target=TARGET, runtime=RUNTIME, params=params)
222226

223227
temp_dir = tvm.contrib.utils.tempdir()
224228

gallery/how_to/work_with_microtvm/micro_tflite.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,9 @@
124124

125125
import os
126126
import numpy as np
127-
import logging
128127

129128
import tvm
130-
import tvm.micro as micro
131129
from tvm.contrib.download import download_testdata
132-
from tvm.contrib import graph_executor, utils
133130
from tvm import relay
134131

135132
model_url = "https://people.linaro.org/~tom.gall/sine_model.tflite"
@@ -179,9 +176,10 @@
179176
# Now we create a build config for relay, turning off two options and then calling relay.build which
180177
# will result in a C source file for the selected TARGET. When running on a simulated target of the
181178
# same architecture as the host (where this Python script is executed) choose "host" below for the
182-
# TARGET and a proper board/VM to run it (Zephyr will create the right QEMU VM based on BOARD. In
183-
# the example below the x86 arch is selected and a x86 VM is picked up accordingly:
179+
# TARGET, the C Runtime as the RUNTIME and a proper board/VM to run it (Zephyr will create the right
180+
# QEMU VM based on BOARD. In the example below the x86 arch is selected and a x86 VM is picked up accordingly:
184181
#
182+
RUNTIME = tvm.relay.backend.Runtime("crt", {"system-lib": True})
185183
TARGET = tvm.target.target.micro("host")
186184
BOARD = "qemu_x86"
187185
#
@@ -210,7 +208,7 @@
210208
with tvm.transform.PassContext(
211209
opt_level=3, config={"tir.disable_vectorize": True}, disabled_pass=["AlterOpLayout"]
212210
):
213-
module = relay.build(mod, target=TARGET, params=params)
211+
module = relay.build(mod, target=TARGET, runtime=RUNTIME, params=params)
214212

215213

216214
# Inspecting the compilation output

include/tvm/ir/module.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,12 @@ class IRModuleNode : public Object {
301301
*/
302302
TVM_DLL void ImportFromStd(const String& path);
303303

304+
/*!
305+
* \brief Should Link Parameters into the module
306+
* \return Whether the Executor is configured to execute with linked parameters (Default: false)
307+
*/
308+
TVM_DLL Bool ShouldLinkParameters() const;
309+
304310
/*!
305311
* \brief The set of imported files.
306312
*/
@@ -468,5 +474,27 @@ TVM_DLL String PrettyPrint(const ObjectRef& node);
468474
*/
469475
TVM_DLL String AsText(const ObjectRef& node, bool show_meta_data = true,
470476
runtime::TypedPackedFunc<String(ObjectRef)> annotate = nullptr);
477+
478+
namespace attr {
479+
480+
/*!
481+
* \brief Executor targetted by the module
482+
*
483+
* Type: Executor
484+
*
485+
* \sa tvm::relay::Executor
486+
*/
487+
constexpr const char* kExecutor = "executor";
488+
489+
/*!
490+
* \brief Runtime target of the module
491+
*
492+
* Type: Runtime
493+
*
494+
* \sa tvm::relay::Runtime
495+
*/
496+
constexpr const char* kRuntime = "runtime";
497+
498+
} // namespace attr
471499
} // namespace tvm
472500
#endif // TVM_IR_MODULE_H_

include/tvm/relay/executor.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ class ExecutorNode : public Object {
5959
/* \brief Additional attributes storing meta-data about the Executor. */
6060
DictAttrs attrs;
6161

62+
/*!
63+
* \brief Should Link Parameters into the module
64+
* \return Whether the Executor is configured to execute modules with linked parameters
65+
*/
66+
Bool ShouldLinkParameters() const {
67+
return name == "aot" || GetAttr<Bool>("link-params").value_or(Bool(false));
68+
}
69+
6270
/*!
6371
* \brief Get an attribute.
6472
*
@@ -114,14 +122,16 @@ class ExecutorNode : public Object {
114122
*/
115123
class Executor : public ObjectRef {
116124
public:
125+
Executor() = default;
126+
117127
/*!
118128
* \brief Create a new Executor object using the registry
119129
* \throws Error if name is not registered
120130
* \param name The name of the executor.
121131
* \param attrs Attributes for the executor.
122132
* \return the new Executor object.
123133
*/
124-
TVM_DLL static Executor Create(String name, Map<String, ObjectRef> attrs);
134+
TVM_DLL static Executor Create(String name, Map<String, ObjectRef> attrs = {});
125135

126136
/*!
127137
* \brief List all registered Executors

include/tvm/relay/runtime.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,16 @@ class RuntimeNode : public Object {
114114
*/
115115
class Runtime : public ObjectRef {
116116
public:
117+
Runtime() = default;
118+
117119
/*!
118120
* \brief Create a new Runtime object using the registry
119121
* \throws Error if name is not registered
120122
* \param name The name of the Runtime.
121123
* \param attrs Attributes for the Runtime.
122124
* \return the new Runtime object.
123125
*/
124-
TVM_DLL static Runtime Create(String name, Map<String, ObjectRef> attrs);
126+
TVM_DLL static Runtime Create(String name, Map<String, ObjectRef> attrs = {});
125127

126128
/*!
127129
* \brief List all registered Runtimes

python/tvm/autotvm/graph_tuner/utils/traverse_graph.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,7 @@ def _traverse_expr(node):
144144
mod = tvm.IRModule.from_expr(relay.Function(params, call))
145145
relay.backend.te_compiler.get().clear()
146146
tracing_target = _replace_device_with_tracing(tvm_target)
147-
build_thread = threading.Thread(
148-
target=relay.build, args=(mod, tracing_target, None, None)
149-
)
147+
build_thread = threading.Thread(target=relay.build, args=(mod, tracing_target))
150148
build_thread.start()
151149
build_thread.join()
152150
elif isinstance(node, Var):

0 commit comments

Comments
 (0)