You are viewing a plain text version of this content. The canonical link for it is here.
Posted to discuss-archive@tvm.apache.org by aca88 via Apache TVM Discuss <no...@discuss.tvm.ai> on 2020/09/17 15:04:59 UTC

[Apache TVM Discuss] [Questions] Interface between Relay Vars and external tensors/te.placeholders?


Hi,

I am wondering if anyone can guide me to how the linking between Relay Vars to `te.placeholders` is done for the internal lowering process and external compiler process.

In the case of external compilers (especially the DNNL), I think that the link is done by either

* [visiting the Var nodes of the Relay graph](https://github.com/apache/incubator-tvm/blob/master/src/relay/backend/contrib/dnnl/codegen.cc#L148)
* [visiting the arguments of the CallNodes](https://github.com/apache/incubator-tvm/blob/master/src/relay/backend/contrib/dnnl/codegen.cc#L62), but here I only see it being used to extract known properties of the tensors. So the actual tensor pointer seems to not be extracted this way.

 Q1: what exactly is this GetRef function doing? 
* I think this is the [GetRef implementation](https://github.com/apache/incubator-tvm/blob/master/include/tvm/runtime/object.h#L844) but I cannot figure it out
* if that is not how we are linking between relay variables and arrays of an external compiler, how is it being done in the DNNL example? 

For the internal lowering process, I have less knowledge of how it is done.

```
import tvm
from tvm import relay

def min_relay_prog():

    x = relay.var('x', shape=(1,3, 224, 224))
    w = relay.var('w', shape=(16, 3, 3, 3))
    b = relay.var('b', shape=(16, ))
    
    conv2d = relay.op.nn.conv2d(x, w,data_layout="NCHW")
    bias = relay.op.nn.bias_add(conv2d, b)
    act = relay.op.nn.relu(bias)
    rfunc = relay.Function([x,b,w], act) #NOTE1
    mod = tvm.IRModule()
    mod["main"] = rfunc
    
    return mod


mod = min_relay_prog()
graph , lfunc, params = relay.build(mod,'c')
```
If I then do `print(lfunc.get_source())`, I get the following output:
```
#include "tvm/runtime/c_runtime_api.h"
#include "tvm/runtime/c_backend_api.h"
void* __tvm_module_ctx = NULL;
#ifdef __cplusplus
extern "C"
#endif
TVM_DLL int32_t fused_nn_conv2d_nn_bias_add_nn_relu_1(void* args, void* arg_type_ids, int32_t num_args, void* out_ret_value, void* out_ret_tcode, void* resource_handle) {
  void* arg0 = (((TVMValue*)args)[0].v_handle);
  int32_t arg0_code = ((int32_t*)arg_type_ids)[(0)];
  void* arg1 = (((TVMValue*)args)[1].v_handle);
  int32_t arg1_code = ((int32_t*)arg_type_ids)[(1)];
  void* arg2 = (((TVMValue*)args)[2].v_handle);
  int32_t arg2_code = ((int32_t*)arg_type_ids)[(2)];
  void* arg3 = (((TVMValue*)args)[3].v_handle);
  int32_t arg3_code = ((int32_t*)arg_type_ids)[(3)];
  void* placeholder = (((DLTensor*)arg0)[0].data);
  void* arg0_shape = (((DLTensor*)arg0)[0].shape);
  void* arg0_strides = (((DLTensor*)arg0)[0].strides);
  int32_t dev_id = (((DLTensor*)arg0)[0].ctx.device_id);
  void* placeholder1 = (((DLTensor*)arg1)[0].data);
  void* arg1_shape = (((DLTensor*)arg1)[0].shape);
  void* arg1_strides = (((DLTensor*)arg1)[0].strides);
  void* placeholder2 = (((DLTensor*)arg2)[0].data);
  void* arg2_shape = (((DLTensor*)arg2)[0].shape);
  void* arg2_strides = (((DLTensor*)arg2)[0].strides);
  void* T_relu = (((DLTensor*)arg3)[0].data);
  void* arg3_shape = (((DLTensor*)arg3)[0].shape);
  void* arg3_strides = (((DLTensor*)arg3)[0].strides);
//rest of output is omitted due to space
```
The `args` variable has all arguments of the fused relay graph. By investigating the rest of the code (which is omitted), it seems that `placeholder` is the input feature map, `placeholder1` is the kernel and `placeholder2` are the biases. This seems to contradict the order in which I declared the inputs to the Relay function (NOTE1 in python code).

I guess this makes sense, since this Relay function just encapsulates the Relay graph of operators. But then that means that, in some part of the lowering/codegen process `args` is being filled either from root to outputs (as FIFO) or from output to root (as stack). I guess the ordering at each operator (like conv2d) is in the order that the `topi` operator is defined (meaning ifm is first argument and kernel is second).

Q2: Is this in general how the `args` are constructed? if not please explain :slight_smile:
*  Where in the code can I actually see how this is done? I have been looking [here](https://github.com/apache/incubator-tvm/blob/master/src/relay/backend/compile_engine.cc#L646) but I feel I'm missing something

Q3: How do the GraphRuntime and the lowered funcs actually communicate?
* where in the code can I see this? 


Thanks





---
[Visit Topic](https://discuss.tvm.apache.org/t/interface-between-relay-vars-and-external-tensors-te-placeholders/7937/1) to respond.

You are receiving this because you enabled mailing list mode.

To unsubscribe from these emails, [click here](https://discuss.tvm.apache.org/email/unsubscribe/a7168cf3326a80faf710f890b56971ddedc7e1433c92f304b68ef0362d7cb5d8).

[Apache TVM Discuss] [Questions] Interface between Relay Vars and external tensors/te.placeholders?

Posted by aca88 via Apache TVM Discuss <no...@discuss.tvm.ai>.

a friendly cc @comaniac @zhiics





---
[Visit Topic](https://discuss.tvm.apache.org/t/interface-between-relay-vars-and-external-tensors-te-placeholders/7937/2) to respond.

You are receiving this because you enabled mailing list mode.

To unsubscribe from these emails, [click here](https://discuss.tvm.apache.org/email/unsubscribe/b5b82a96a96a1b35dc56b2256a05be82cca25aa37e7a42cf9ae60dcdd36468b4).