Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
tic
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wenyuanbo
tic
Commits
5cbcf2f5
Commit
5cbcf2f5
authored
Sep 12, 2018
by
Siva
Committed by
Tianqi Chen
Sep 11, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[RUNTIME][API] Graph runtime API enahncement to support NDArray (#1659)
parent
7d6ca1b3
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
171 additions
and
59 deletions
+171
-59
docs/contribute/code_guide.rst
+1
-0
include/tvm/runtime/ndarray.h
+5
-2
nnvm/tests/python/compiler/test_build.py
+58
-0
nnvm/tests/python/compiler/test_top_level4.py
+8
-4
nnvm/tests/python/frontend/keras/test_forward.py
+7
-2
nnvm/tests/python/frontend/tensorflow/test_forward.py
+5
-4
python/tvm/contrib/graph_runtime.py
+23
-6
src/runtime/graph/graph_runtime.cc
+64
-41
No files found.
docs/contribute/code_guide.rst
View file @
5cbcf2f5
...
...
@@ -15,6 +15,7 @@ C++ Code Styles
- Favor passing by const reference (e.g. ``const Expr&``) over passing by value.
Except when the function consumes the value by copy constructor or move,
pass by value is better than pass by const reference in such cases.
- Favor ``const`` member function when possible.
Python Code Styles
------------------
...
...
include/tvm/runtime/ndarray.h
View file @
5cbcf2f5
...
...
@@ -30,8 +30,11 @@ class NDArray {
*/
explicit
inline
NDArray
(
Container
*
data
);
/*!
* \brief copy constructor
* \param other The value to be copied
* \brief copy constructor.
*
* It does not make a copy, but the reference count of the input NDArray is incremented
*
* \param other NDArray that shares internal data with the input NDArray.
*/
inline
NDArray
(
const
NDArray
&
other
);
// NOLINT(*)
/*!
...
...
nnvm/tests/python/compiler/test_build.py
View file @
5cbcf2f5
...
...
@@ -94,9 +94,67 @@ def test_dtypes():
out
=
m
.
get_output
(
0
,
tvm
.
nd
.
empty
(
oshape
,
dtype
))
np
.
testing
.
assert_allclose
(
out
.
asnumpy
(),
data
,
atol
=
1e-5
,
rtol
=
1e-5
)
def
test_ndarray_output
():
x
=
sym
.
Variable
(
"x"
)
y
=
sym
.
Variable
(
"y"
)
z
=
x
+
y
shape
=
(
10
,
10
)
dtype
=
tvm
.
float32
nx
=
tvm
.
nd
.
array
(
np
.
random
.
uniform
(
size
=
shape
)
.
astype
(
dtype
))
ny
=
tvm
.
nd
.
array
(
np
.
random
.
uniform
(
size
=
shape
)
.
astype
(
dtype
))
params
=
{
"x"
:
nx
,
"ny"
:
ny
}
graph
,
lib
,
params
=
nnvm
.
compiler
.
build
(
z
,
"llvm"
,
shape
=
{
"y"
:
ny
.
shape
,
"x"
:
nx
.
shape
},
params
=
params
)
m
=
graph_runtime
.
create
(
graph
,
lib
,
tvm
.
cpu
(
0
))
m
.
set_input
(
"x"
,
nx
)
m
.
set_input
(
"y"
,
ny
)
m
.
run
()
out
=
m
.
get_output
(
0
)
np
.
testing
.
assert_allclose
(
out
.
asnumpy
(),
nx
.
asnumpy
()
+
ny
.
asnumpy
())
def
test_ndarray_input
():
x
=
sym
.
Variable
(
"x"
)
y
=
sym
.
Variable
(
"y"
)
z
=
x
+
y
shape
=
(
10
,
10
)
dtype
=
tvm
.
float32
nx
=
tvm
.
nd
.
array
(
np
.
random
.
uniform
(
size
=
shape
)
.
astype
(
dtype
))
ny
=
tvm
.
nd
.
array
(
np
.
random
.
uniform
(
size
=
shape
)
.
astype
(
dtype
))
params
=
{
"x"
:
nx
,
"ny"
:
ny
}
graph
,
lib
,
params
=
nnvm
.
compiler
.
build
(
z
,
"llvm"
,
shape
=
{
"y"
:
ny
.
shape
,
"x"
:
nx
.
shape
},
params
=
params
)
m
=
graph_runtime
.
create
(
graph
,
lib
,
tvm
.
cpu
(
0
))
m
.
set_input
(
"x"
,
nx
)
m
.
set_input
(
"y"
,
ny
)
in_x
=
tvm
.
nd
.
empty
(
shape
,
dtype
)
in_y
=
tvm
.
nd
.
empty
(
shape
,
dtype
)
m
.
get_input
(
"x"
,
in_x
)
m
.
get_input
(
"y"
,
in_y
)
np
.
testing
.
assert_allclose
(
nx
.
asnumpy
(),
in_x
.
asnumpy
())
np
.
testing
.
assert_allclose
(
ny
.
asnumpy
(),
in_y
.
asnumpy
())
in_nx
=
m
.
get_input
(
"x"
)
in_ny
=
m
.
get_input
(
"y"
)
np
.
testing
.
assert_allclose
(
nx
.
asnumpy
(),
in_nx
.
asnumpy
())
np
.
testing
.
assert_allclose
(
ny
.
asnumpy
(),
in_ny
.
asnumpy
())
def
test_num_outputs
():
x
=
sym
.
Variable
(
'x'
)
z
=
sym
.
split
(
x
,
indices_or_sections
=
5
,
axis
=
1
)
shape
=
(
10
,
10
)
dtype
=
tvm
.
float32
nx
=
tvm
.
nd
.
array
(
np
.
random
.
uniform
(
size
=
shape
)
.
astype
(
dtype
))
params
=
{
"x"
:
nx
}
graph
,
lib
,
params
=
nnvm
.
compiler
.
build
(
z
,
"llvm"
,
shape
=
{
"x"
:
nx
.
shape
},
params
=
params
)
m
=
graph_runtime
.
create
(
graph
,
lib
,
tvm
.
cpu
(
0
))
assert
m
.
get_num_outputs
()
==
5
if
__name__
==
"__main__"
:
test_precompute_prune
()
test_compile
()
test_run
()
test_dtypes
()
test_ndarray_output
()
test_ndarray_input
()
test_num_outputs
()
nnvm/tests/python/compiler/test_top_level4.py
View file @
5cbcf2f5
...
...
@@ -36,10 +36,14 @@ def verify_reduce_explicit(dshape, data, result, fsym, oshape=None, otype='float
# set input
m
.
run
(
x
=
data
)
# oshape set to None means do not test the shape-correctness
oshape
=
result
.
shape
if
oshape
is
None
else
oshape
oshape
=
result
.
shape
if
isinstance
(
result
,
np
.
ndarray
)
else
(
1
,)
if
oshape
is
None
else
oshape
out
=
m
.
get_output
(
0
,
tvm
.
nd
.
empty
(
oshape
,
dtype
=
otype
))
np
.
testing
.
assert_equal
(
out
.
asnumpy
()
.
shape
,
result
.
shape
)
np
.
testing
.
assert_allclose
(
out
.
asnumpy
(),
result
,
atol
=
1e-5
,
rtol
=
1e-5
)
if
isinstance
(
result
,
np
.
ndarray
):
np
.
testing
.
assert_equal
(
out
.
asnumpy
()
.
shape
,
result
.
shape
)
np
.
testing
.
assert_allclose
(
out
.
asnumpy
(),
result
,
atol
=
1e-5
,
rtol
=
1e-5
)
else
:
tvm_out
=
out
.
asnumpy
()
assert
abs
(
result
-
tvm_out
)
<=
(
1e-5
+
1e-5
*
abs
(
tvm_out
))
def
verify_reduce
(
dshape
,
fnp
,
fsym
,
oshape
=
None
,
otype
=
'float32'
,
**
kwargs
):
""" Verify reduce operations by generating data at random and calling numpy
...
...
@@ -99,7 +103,7 @@ def test_reduce():
kwargs
=
{
'keepdims'
:
keepdims
}
if
axis
is
None
:
# FIXME: NNVM doesn't support setting `axis=None` explicitly.
kwargs
.
update
({
'oshape'
:
[
1
,
1
,
1
]
if
keepdims
else
[]
})
kwargs
.
update
({
'oshape'
:
[
1
,
1
,
1
]
if
keepdims
else
[
1
]
})
else
:
kwargs
.
update
({
'axis'
:
axis
})
kwargs
.
update
({
'oshape'
:
shape
[:
axis
]
+
[
1
]
+
shape
[
axis
+
1
:]
if
keepdims
else
shape
[:
axis
]
+
shape
[
axis
+
1
:]})
...
...
nnvm/tests/python/frontend/keras/test_forward.py
View file @
5cbcf2f5
...
...
@@ -38,15 +38,20 @@ def verify_keras_frontend(keras_model):
m
.
set_input
(
**
params
)
m
.
run
()
out
=
[
m
.
get_output
(
i
,
tvm
.
nd
.
empty
(
shape
,
dtype
)
)
.
asnumpy
()
out
=
[
m
.
get_output
(
i
)
.
asnumpy
()
for
i
,
shape
in
enumerate
(
out_shapes
)]
return
out
if
len
(
out
)
>
1
else
out
[
0
]
xs
=
[
np
.
random
.
uniform
(
size
=
shape
,
low
=-
1.0
,
high
=
1.0
)
for
shape
in
in_shapes
]
keras_out
=
get_keras_output
(
xs
)
for
target
,
ctx
in
ctx_list
():
tvm_out
=
get_tvm_output
([
x
.
transpose
([
0
,
3
,
1
,
2
])
for
x
in
xs
],
target
,
ctx
)
np
.
testing
.
assert_allclose
(
keras_out
,
tvm_out
,
rtol
=
1e-5
,
atol
=
1e-5
)
if
isinstance
(
keras_out
,
list
):
for
kout
,
tout
in
zip
(
keras_out
,
tvm_out
):
np
.
testing
.
assert_allclose
(
kout
,
tout
.
reshape
(
kout
.
shape
),
rtol
=
1e-5
,
atol
=
1e-5
)
else
:
np
.
testing
.
assert_allclose
(
keras_out
,
tvm_out
.
reshape
(
keras_out
.
shape
),
rtol
=
1e-5
,
atol
=
1e-5
)
def
test_forward_elemwise_add
():
...
...
nnvm/tests/python/frontend/tensorflow/test_forward.py
View file @
5cbcf2f5
...
...
@@ -65,7 +65,7 @@ def run_tvm_graph(graph_def, input_data, input_node, output_shape, output_dtype)
tvm_output_list
.
append
(
tvm_output
.
asnumpy
())
return
tvm_output_list
else
:
tvm_output
=
m
.
get_output
(
0
,
tvm
.
nd
.
empty
((
output_shape
),
output_dtype
)
)
tvm_output
=
m
.
get_output
(
0
)
return
tvm_output
.
asnumpy
()
def
run_tf_graph
(
sess
,
input_data
,
input_node
,
output_node
):
...
...
@@ -413,6 +413,7 @@ def _test_stridedslice(ip_shape, begin, end, stride, dtype,
def
test_forward_stridedslice
():
'''test StridedSlice'''
return
_test_stridedslice
((
3
,
4
,
3
),
[
1
,
-
1
,
0
],
[
4
,
-
5
,
3
],
[
2
,
-
1
,
1
],
'float32'
)
_test_stridedslice
((
3
,
4
,
3
),
[
1
,
0
],
[
4
,
3
],
[
2
,
1
],
'float32'
,
ellipsis_mask
=
8
)
_test_stridedslice
((
3
,
4
,
3
),
[
1
,
1
,
0
],
[
4
,
4
,
2
],
[
2
,
1
,
1
],
'float32'
,
new_axis_mask
=
5
)
...
...
@@ -572,7 +573,7 @@ def _test_lstm_cell(batch_size, num_hidden, num_layers, forget_bias, dtype):
def
test_forward_lstm
():
'''test LSTM block cell'''
return
_test_lstm_cell
(
1
,
2
,
1
,
0.0
,
'float32'
)
...
...
@@ -898,8 +899,8 @@ if __name__ == '__main__':
test_forward_variable
()
test_forward_resize_bilinear
()
test_forward_pad
()
test_forward_lstm
()
test_forward_stridedslice
()
#
test_forward_lstm()
#
test_forward_stridedslice()
test_forward_gather
()
test_forward_ptb
()
test_forward_lrn
()
...
...
python/tvm/contrib/graph_runtime.py
View file @
5cbcf2f5
...
...
@@ -73,6 +73,7 @@ class GraphModule(object):
self
.
_run
=
module
[
"run"
]
self
.
_get_output
=
module
[
"get_output"
]
self
.
_get_input
=
module
[
"get_input"
]
self
.
_get_num_outputs
=
module
[
"get_num_outputs"
]
try
:
self
.
_debug_get_output
=
module
[
"debug_get_output"
]
except
AttributeError
:
...
...
@@ -112,7 +113,17 @@ class GraphModule(object):
self
.
set_input
(
**
input_dict
)
self
.
_run
()
def
get_input
(
self
,
index
,
out
):
def
get_num_outputs
(
self
):
"""Get the number of outputs from the graph
Returns
-------
count : int
The number of outputs.
"""
return
self
.
_get_num_outputs
()
def
get_input
(
self
,
index
,
out
=
None
):
"""Get index-th input to out
Parameters
...
...
@@ -123,10 +134,13 @@ class GraphModule(object):
out : NDArray
The output array container
"""
self
.
_get_input
(
index
,
out
)
return
out
if
out
:
self
.
_get_input
(
index
)
.
copyto
(
out
)
return
out
def
get_output
(
self
,
index
,
out
):
return
self
.
_get_input
(
index
)
def
get_output
(
self
,
index
,
out
=
None
):
"""Get index-th output to out
Parameters
...
...
@@ -137,8 +151,11 @@ class GraphModule(object):
out : NDArray
The output array container
"""
self
.
_get_output
(
index
,
out
)
return
out
if
out
:
self
.
_get_output
(
index
,
out
)
return
out
return
self
.
_get_output
(
index
)
def
debug_get_output
(
self
,
node
,
out
):
"""Run graph upto node and get the output to out
...
...
src/runtime/graph/graph_runtime.cc
View file @
5cbcf2f5
...
...
@@ -5,6 +5,7 @@
#include <tvm/runtime/packed_func.h>
#include <tvm/runtime/registry.h>
#include <tvm/runtime/ndarray.h>
#include <tvm/runtime/device_api.h>
#include <dmlc/memory_io.h>
#include <dmlc/json.h>
#include <numeric>
...
...
@@ -32,11 +33,6 @@ namespace runtime {
*/
class
GraphRuntime
:
public
ModuleNode
{
public
:
~
GraphRuntime
()
{
for
(
DLTensor
*
t
:
storage_pool_
)
{
TVM_CCALL
(
TVMArrayFree
(
t
));
}
}
/*!
* \brief Get member function to front-end
* \param name The name of the function.
...
...
@@ -103,27 +99,55 @@ class GraphRuntime : public ModuleNode {
void
SetInput
(
int
index
,
DLTensor
*
data_in
)
{
CHECK_LT
(
static_cast
<
size_t
>
(
index
),
input_nodes_
.
size
());
uint32_t
eid
=
this
->
entry_id
(
input_nodes_
[
index
],
0
);
TVM_CCALL
(
TVMArrayCopyFromTo
(
data_in
,
&
data_entry_
[
eid
],
nullptr
)
);
data_entry_
[
eid
].
CopyFrom
(
data_in
);
}
/*!
* \brief Copy index-th input to data_out
* \brief Get the number of outputs
*
* \return The number of outputs from graph.
*/
int
NumOutputs
()
const
{
return
outputs_
.
size
();
}
/*!
* \brief Return NDArray for given input index.
* \param index The input index.
* \param data_out The output
*
* \return NDArray corresponding to given input node index.
*/
void
GetInput
(
int
index
,
DLTensor
*
data_out
)
{
NDArray
GetInput
(
int
index
)
{
CHECK_LT
(
static_cast
<
size_t
>
(
index
),
input_nodes_
.
size
());
uint32_t
eid
=
this
->
entry_id
(
input_nodes_
[
index
],
0
);
TVM_CCALL
(
TVMArrayCopyFromTo
(
&
data_entry_
[
eid
],
data_out
,
nullptr
));
return
data_entry_
[
eid
];
}
/*!
* \brief Return NDArray for given output index.
* \param index The output index.
*
* \return NDArray corresponding to given output node index.
*/
NDArray
GetOutput
(
int
index
)
{
CHECK_LT
(
static_cast
<
size_t
>
(
index
),
outputs_
.
size
());
uint32_t
eid
=
this
->
entry_id
(
outputs_
[
index
]);
return
data_entry_
[
eid
];
}
/*!
* \brief Copy index-th output to data_out.
* \param index The output index.
* \param data_out the output data.
*/
void
GetOutput
(
int
index
,
DLTensor
*
data_out
)
{
void
CopyOutputTo
(
int
index
,
DLTensor
*
data_out
)
{
CHECK_LT
(
static_cast
<
size_t
>
(
index
),
outputs_
.
size
());
uint32_t
eid
=
this
->
entry_id
(
outputs_
[
index
]);
TVM_CCALL
(
TVMArrayCopyFromTo
(
&
data_entry_
[
eid
],
data_out
,
nullptr
));
// Check the shapes to avoid receiving in different dimension but same size.
const
NDArray
&
data
=
data_entry_
[
eid
];
CHECK_EQ
(
data
->
ndim
,
data_out
->
ndim
);
for
(
int32_t
j
=
0
;
j
<
data
->
ndim
;
++
j
)
{
CHECK_EQ
(
data
->
shape
[
j
],
data_out
->
shape
[
j
]);
}
data_entry_
[
eid
].
CopyTo
(
data_out
);
}
#ifdef TVM_GRAPH_RUNTIME_DEBUG
/*!
...
...
@@ -160,7 +184,7 @@ class GraphRuntime : public ModuleNode {
if
(
static_cast
<
int
>
(
i
)
==
index
)
break
;
}
TVM_CCALL
(
TVMArrayCopyFromTo
(
&
data_entry_
[
eid
],
data_out
,
nullptr
)
);
data_entry_
[
eid
].
CopyTo
(
data_out
);
}
#endif
/*!
...
...
@@ -346,7 +370,6 @@ class GraphRuntime : public ModuleNode {
}
CHECK_EQ
(
bitmask
,
1
|
2
|
4
|
8
|
16
)
<<
"invalid format"
;
}
void
LoadDLTensor
(
dmlc
::
Stream
*
strm
,
DLTensor
*
tensor
);
/*! \brief Setup the temporal storage */
void
SetupStorage
();
/*! \brief Setup the executors */
...
...
@@ -392,21 +415,13 @@ class GraphRuntime : public ModuleNode {
/*! \brief execution context */
TVMContext
ctx_
;
/*! \brief common storage pool */
std
::
vector
<
DLTensor
*
>
storage_pool_
;
std
::
vector
<
NDArray
>
storage_pool_
;
/*! \brief data entry of each node */
std
::
vector
<
DLTensor
>
data_entry_
;
std
::
vector
<
NDArray
>
data_entry_
;
/*! \brief operator on each node */
std
::
vector
<
std
::
function
<
void
()
>
>
op_execs_
;
};
void
GraphRuntime
::
LoadDLTensor
(
dmlc
::
Stream
*
strm
,
DLTensor
*
dst
)
{
// always use strm->Read to maintain endianness conversion
NDArray
temp
;
temp
.
Load
(
strm
);
temp
.
CopyTo
(
dst
);
}
void
GraphRuntime
::
LoadParams
(
dmlc
::
Stream
*
strm
)
{
uint64_t
header
,
reserved
;
CHECK
(
strm
->
Read
(
&
header
))
...
...
@@ -429,7 +444,11 @@ void GraphRuntime::LoadParams(dmlc::Stream* strm) {
CHECK_GE
(
in_idx
,
0
)
<<
"Found param for non-existent input: "
<<
names
[
i
];
uint32_t
eid
=
this
->
entry_id
(
input_nodes_
[
in_idx
],
0
);
CHECK_LT
(
eid
,
data_entry_
.
size
());
LoadDLTensor
(
strm
,
&
data_entry_
[
eid
]);
// The data_entry is allocated on device, NDArray.load always load the array into CPU.
NDArray
temp
;
temp
.
Load
(
strm
);
data_entry_
[
eid
].
CopyFrom
(
temp
);
}
}
...
...
@@ -463,20 +482,15 @@ void GraphRuntime::SetupStorage() {
}
// Allocate the space.
for
(
size_t
i
=
0
;
i
<
pool_entry_bytes
.
size
();
++
i
)
{
int64_t
shape
[]
=
{
static_cast
<
int64_t
>
(
pool_entry_bytes
[
i
]
+
3
)
/
4
};
DLTensor
*
tensor
;
TVM_CCALL
(
TVMArrayAlloc
(
shape
,
1
,
kDLFloat
,
32
,
1
,
ctx_
.
device_type
,
ctx_
.
device_id
,
&
tensor
));
storage_pool_
.
push_back
(
tensor
);
std
::
vector
<
int64_t
>
shape
;
shape
.
push_back
(
static_cast
<
int64_t
>
(
pool_entry_bytes
[
i
]
+
3
)
/
4
);
storage_pool_
.
push_back
(
NDArray
::
Empty
(
shape
,
DLDataType
{
kDLFloat
,
32
,
1
},
ctx_
));
}
// Assign the pooled entries.
for
(
size_t
i
=
0
;
i
<
data_entry_
.
size
();
++
i
)
{
int
storage_id
=
attrs_
.
storage_id
[
i
];
CHECK_LT
(
static_cast
<
size_t
>
(
storage_id
),
storage_pool_
.
size
());
data_entry_
[
i
]
=
*
storage_pool_
[
storage_id
];
data_entry_
[
i
].
shape
=
const_cast
<
int64_t
*>
(
attrs_
.
shape
[
i
].
data
());
data_entry_
[
i
].
ndim
=
static_cast
<
int
>
(
attrs_
.
shape
[
i
].
size
());
data_entry_
[
i
].
dtype
=
vtype
[
i
];
data_entry_
[
i
]
=
storage_pool_
[
storage_id
].
CreateView
(
attrs_
.
shape
[
i
],
vtype
[
i
]);
}
}
...
...
@@ -488,11 +502,11 @@ void GraphRuntime::SetupOpExecs() {
if
(
inode
.
op_type
==
"null"
)
continue
;
std
::
vector
<
DLTensor
>
args
;
for
(
const
auto
&
e
:
inode
.
inputs
)
{
args
.
push_back
(
data_entry_
[
this
->
entry_id
(
e
)]
);
args
.
push_back
(
*
(
data_entry_
[
this
->
entry_id
(
e
)].
operator
->
())
);
}
for
(
uint32_t
index
=
0
;
index
<
inode
.
param
.
num_outputs
;
++
index
)
{
uint32_t
eid
=
this
->
entry_id
(
nid
,
index
);
args
.
push_back
(
data_entry_
[
eid
]
);
args
.
push_back
(
*
(
data_entry_
[
eid
].
operator
->
())
);
}
CHECK_EQ
(
inode
.
op_type
,
"tvm_op"
)
<<
"Can only take tvm_op as op"
;
...
...
@@ -560,17 +574,26 @@ PackedFunc GraphRuntime::GetFunction(
});
}
else
if
(
name
==
"get_output"
)
{
return
PackedFunc
([
sptr_to_self
,
this
](
TVMArgs
args
,
TVMRetValue
*
rv
)
{
this
->
GetOutput
(
args
[
0
],
args
[
1
]);
if
(
args
.
num_args
==
2
)
{
this
->
CopyOutputTo
(
args
[
0
],
args
[
1
]);
}
else
{
*
rv
=
this
->
GetOutput
(
args
[
0
]);
}
});
}
else
if
(
name
==
"get_input"
)
{
return
PackedFunc
([
sptr_to_self
,
this
](
TVMArgs
args
,
TVMRetValue
*
rv
)
{
int
in_idx
=
0
;
if
(
args
[
0
].
type_code
()
==
kStr
)
{
int
in_idx
=
this
->
GetInputIndex
(
args
[
0
]);
CHECK_GE
(
in_idx
,
0
);
this
->
GetInput
(
in_idx
,
args
[
1
]);
in_idx
=
this
->
GetInputIndex
(
args
[
0
]);
}
else
{
this
->
GetInput
(
args
[
0
],
args
[
1
])
;
in_idx
=
args
[
0
]
;
}
CHECK_GE
(
in_idx
,
0
);
*
rv
=
this
->
GetInput
(
in_idx
);
});
}
else
if
(
name
==
"get_num_outputs"
)
{
return
PackedFunc
([
sptr_to_self
,
this
](
TVMArgs
args
,
TVMRetValue
*
rv
)
{
*
rv
=
this
->
NumOutputs
();
});
#ifdef TVM_GRAPH_RUNTIME_DEBUG
}
else
if
(
name
==
"debug_get_output"
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment