Skip to content

Commit 9c602ea

Browse files
committed
Generate correct output tensor names in C Interface API
Change-Id: I90d86aef7d8b93fb937391a87f79ae9362207058
1 parent 2a840a3 commit 9c602ea

File tree

13 files changed

+239
-68
lines changed

13 files changed

+239
-68
lines changed

apps/microtvm/ethosu/src/demo_bare_metal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ int main(int argc, char** argv) {
4040

4141
printf("Running inference\n");
4242
struct tvmgen_default_outputs outputs = {
43-
.output = output,
43+
.MobilenetV2_Predictions_Reshape_11 = output,
4444
};
4545
struct tvmgen_default_inputs inputs = {
4646
.tfl_quantize = input,

python/tvm/micro/model_library_format.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,13 @@ def _get_inputs_and_outputs_from_module(mod):
270270
main_func = _get_main_relay_func(mod)
271271
inputs = [argument.name_hint for argument in main_func.params]
272272

273-
outputs = ["output"]
274-
if isinstance(main_func.ret_type, TupleType):
275-
outputs = _convert_tuple_to_outputs(main_func.ret_type)
273+
if "output_tensor_names" in main_func.attrs:
274+
outputs = main_func.attrs["output_tensor_names"]
275+
else:
276+
if isinstance(main_func.ret_type, TupleType):
277+
outputs = _convert_tuple_to_outputs(main_func.ret_type)
278+
else:
279+
outputs = ["output"]
276280

277281
return inputs, outputs
278282

python/tvm/relay/frontend/tflite.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"""Tensorflow lite frontend."""
1919
import itertools
2020
import math
21+
import re
2122

2223
import numpy as np
2324
import tvm
@@ -3769,6 +3770,15 @@ def from_tflite(model, shape_dict=None, dtype_dict=None, op_converter=OperatorCo
37693770
params = {k: _nd.array(np.array(v)) for k, v in exp_tab.params.items()}
37703771
outputs = [exp_tab.get_expr(get_tensor_name(subgraph, i)) for i in model_outputs]
37713772
outputs = outputs[0] if len(outputs) == 1 else _expr.Tuple(outputs)
3772-
func = _function.Function(analysis.free_vars(outputs), outputs)
3773+
attrs = tvm.ir.make_node(
3774+
"DictAttrs",
3775+
**{
3776+
"output_tensor_names": [
3777+
re.sub(r"\W", "_", get_tensor_name(subgraph, model_output))
3778+
for model_output in model_outputs
3779+
]
3780+
},
3781+
)
3782+
func = _function.Function(analysis.free_vars(outputs), outputs, attrs=attrs)
37733783
mod = IRModule.from_expr(func)
37743784
return mod, params

src/relay/backend/aot_executor_codegen.cc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,27 @@ class AOTExecutorCodegen : public MixedModeVisitor {
957957
Array<tir::Var>(tir_main_func->params.begin(),
958958
tir_main_func->params.begin() + tir_main_func->params.size() -
959959
return_sid_.size() - pool_vars.size() - devices.size());
960-
ret.metadata = ExecutorCodegenMetadata(inputs, pool_vars, devices, return_sid_.size(),
960+
961+
std::vector<String> output_var_names;
962+
if (auto opt = func->GetAttr<Array<String>>("output_tensor_names")) {
963+
Array<String> output_tensor_names = opt.value();
964+
for (size_t i = 0; i < output_tensor_names.size(); ++i) {
965+
output_var_names.push_back(output_tensor_names[i]);
966+
}
967+
}
968+
969+
// If output names have not been specified then generate default output names
970+
if (output_var_names.size() == 0) {
971+
if (return_sid_.size() == 1) {
972+
output_var_names.push_back(String("output"));
973+
} else {
974+
for (size_t i = 0; i < return_sid_.size(); ++i) {
975+
output_var_names.push_back(String("output" + std::to_string(i)));
976+
}
977+
}
978+
}
979+
980+
ret.metadata = ExecutorCodegenMetadata(inputs, pool_vars, devices, output_var_names,
961981
runtime::kTvmExecutorAot, mod_name, interface_api,
962982
use_unpacked_api_, pool_var_info);
963983
return ret;

src/relay/backend/utils.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,14 +179,14 @@ TVM_STATIC_IR_FUNCTOR(ReprPrinter, vtable)
179179
});
180180

181181
ExecutorCodegenMetadata::ExecutorCodegenMetadata(
182-
Array<tir::Var> inputs, Array<tir::Var> pools, Array<String> devices, Integer num_outputs,
182+
Array<tir::Var> inputs, Array<tir::Var> pools, Array<String> devices, Array<String> outputs,
183183
String executor, String mod_name, String interface_api, bool unpacked_api,
184184
Map<tir::Var, tir::usmp::AllocatedPoolInfo> pool_inputs) {
185185
auto n = make_object<ExecutorCodegenMetadataNode>();
186186
n->inputs = inputs;
187187
n->pools = pools;
188188
n->devices = devices;
189-
n->num_outputs = num_outputs;
189+
n->outputs = outputs;
190190
n->executor = executor;
191191
n->interface_api = interface_api;
192192
n->unpacked_api = unpacked_api;

src/relay/backend/utils.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ class ExecutorCodegenMetadataNode : public Object {
6161
public:
6262
/*! \brief input information for the main function */
6363
Array<tir::Var> inputs;
64+
/*! \brief output information for the main function */
65+
Array<String> outputs;
6466
/*! \brief pool information for the main function */
6567
Array<tir::Var> pools;
66-
/*! \brief number of outputs of the main function */
67-
Integer num_outputs = 1;
6868
/*! \brief device contexts information for the main function */
6969
Array<String> devices;
7070
/*! \brief the executor to be used to run the model */
@@ -81,7 +81,7 @@ class ExecutorCodegenMetadataNode : public Object {
8181
void VisitAttrs(tvm::AttrVisitor* v) {
8282
v->Visit("inputs", &inputs);
8383
v->Visit("pools", &pools);
84-
v->Visit("num_outputs", &num_outputs);
84+
v->Visit("outputs", &outputs);
8585
v->Visit("devices", &devices);
8686
v->Visit("executor", &executor);
8787
v->Visit("unpacked_api", &unpacked_api);
@@ -98,7 +98,7 @@ class ExecutorCodegenMetadataNode : public Object {
9898
class ExecutorCodegenMetadata : public ObjectRef {
9999
public:
100100
TVM_DLL ExecutorCodegenMetadata(Array<tir::Var> inputs, Array<tir::Var> pools,
101-
Array<String> devices, Integer num_outputs, String executor,
101+
Array<String> devices, Array<String> outputs, String executor,
102102
String mod_name, String interface_api = "packed",
103103
bool unpacked_api = false,
104104
Map<tir::Var, tir::usmp::AllocatedPoolInfo> pool_inputs =

src/target/source/source_module.cc

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ class CSourceCrtMetadataModuleNode : public runtime::ModuleNode {
273273
}
274274
call_args_ss << " " << input_var->name_hint << ",";
275275
}
276-
for (int i = 0; i < metadata_->num_outputs->value; ++i) {
276+
for (unsigned int i = 0; i < metadata_->outputs.size(); ++i) {
277277
call_args_ss << "void* output" << i << ",";
278278
}
279279
for (const tir::Var& pool_var : metadata_->pools) {
@@ -300,7 +300,7 @@ class CSourceCrtMetadataModuleNode : public runtime::ModuleNode {
300300
for (unsigned int i = 0; i < metadata_->inputs.size(); ++i) {
301301
call_args_ss << "((DLTensor*)(((TVMValue*)args)[" << i << "].v_handle))[0].data,";
302302
}
303-
for (int i = 0; i < metadata_->num_outputs->value; ++i) {
303+
for (unsigned int i = 0; i < metadata_->outputs.size(); ++i) {
304304
int j = metadata_->inputs.size() + i;
305305
call_args_ss << "((DLTensor*)(((TVMValue*)args)[" << j << "].v_handle))[0].data,";
306306
}
@@ -328,7 +328,7 @@ class CSourceCrtMetadataModuleNode : public runtime::ModuleNode {
328328
entrypoint_arg_count++;
329329
run_func_arg_count++;
330330
}
331-
for (int i = 0; i < metadata_->num_outputs->value; i++) {
331+
for (unsigned int i = 0; i < metadata_->outputs.size(); i++) {
332332
run_func_to_entry_point_args[run_func_arg_count] = Integer(entrypoint_arg_count);
333333
entrypoint_arg_count++;
334334
run_func_arg_count++;
@@ -356,7 +356,7 @@ class CSourceCrtMetadataModuleNode : public runtime::ModuleNode {
356356

357357
// We are creating a copy of the set of pointers
358358
size_t number_of_io_tensors =
359-
metadata_->inputs.size() + metadata_->num_outputs->value + metadata_->pools.size();
359+
metadata_->inputs.size() + metadata_->outputs.size() + metadata_->pools.size();
360360
code_ << "TVMValue tensors[" << number_of_io_tensors << "];\n";
361361

362362
std::unordered_map<int, ObjectRef> run_func_to_entry_point_args =
@@ -395,7 +395,7 @@ class CSourceCrtMetadataModuleNode : public runtime::ModuleNode {
395395
}
396396
call_args_ss << " " << relay::backend::SanitizeName(input_var->name_hint) << ",";
397397
}
398-
for (int i = 0; i < metadata_->num_outputs->value; ++i) {
398+
for (unsigned int i = 0; i < metadata_->outputs.size(); ++i) {
399399
call_args_ss << "void* output" << i << ",";
400400
}
401401
for (const tir::Var& pool_var : metadata_->pools) {
@@ -449,13 +449,11 @@ class CSourceCrtMetadataModuleNode : public runtime::ModuleNode {
449449
for (const auto& input : metadata_->inputs) {
450450
call_args_ss << "inputs->" << relay::backend::SanitizeName(input->name_hint) << ",";
451451
}
452-
if (metadata_->num_outputs->value == 1) {
453-
call_args_ss << "outputs->output,";
454-
} else {
455-
for (int i = 0; i < metadata_->num_outputs->value; ++i) {
456-
call_args_ss << "outputs->output" << i << ",";
457-
}
452+
for (const auto& output : metadata_->outputs) {
453+
call_args_ss << "outputs->" << relay::backend::SanitizeName(output);
454+
call_args_ss << ",";
458455
}
456+
459457
for (const tir::Var& pool_var : metadata_->pools) {
460458
String pool_name = metadata_->pool_inputs.value()[pool_var]->pool_info->pool_name;
461459
if (IsInternalWorkspaceBuffer(pool_var)) {

tests/python/contrib/test_ethosu/infra.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,10 @@ def generate_ref_data_tflite(model):
306306
interpreter.set_tensor(index, value)
307307
interpreter.invoke()
308308

309-
expected_output_data = [
310-
interpreter.get_tensor(output_detail["index"]) for output_detail in output_details
311-
]
309+
expected_output_data = {
310+
output_detail["name"]: interpreter.get_tensor(output_detail["index"])
311+
for output_detail in output_details
312+
}
312313

313314
return input_data, expected_output_data
314315

tests/python/contrib/test_ethosu/test_codegen.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ def rounding_right_shift(lhs, rhs):
754754
"ifm": lhs,
755755
"ifm2": rhs,
756756
}
757-
output_data = generate_output_data(input_data)
757+
output_data = {"output": generate_output_data(input_data)[0]}
758758
ethosu_mod = _create_ethosu_partition(cpu_mod)
759759

760760
_compare_ethosu_with_reference(ethosu_mod, input_data, output_data, accel_type)
@@ -781,7 +781,7 @@ def generate_output_data(input_data):
781781

782782
cpu_mod = create_model()
783783
input_data = {"ifm": np.random.randint(-120, high=120, size=ifm_shape, dtype="int8")}
784-
output_data = generate_output_data(input_data)
784+
output_data = {"output": generate_output_data(input_data)[0]}
785785
ethosu_mod = _create_ethosu_partition(cpu_mod)
786786

787787
_compare_ethosu_with_reference(
@@ -910,7 +910,7 @@ def clz_comp(n):
910910

911911
cpu_mod = create_model()
912912
input_data = {"ifm": np.random.randint(-500000, high=500000, size=ifm_shape, dtype="int32")}
913-
output_data = generate_output_data(input_data)
913+
output_data = {"output": generate_output_data(input_data)[0]}
914914
ethosu_mod = _create_ethosu_partition(cpu_mod)
915915

916916
_compare_ethosu_with_reference(ethosu_mod, input_data, output_data, accel_type)

tests/python/contrib/test_ethosu/test_lookup_table.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def test_random_lut(accel_type):
154154
compiled_models = infra.build_source(
155155
mod,
156156
{"ifm": in_data},
157-
out_data,
157+
{"output": out_data},
158158
accel_type,
159159
)
160160

0 commit comments

Comments
 (0)