This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TDA4VM: Re: Conversion of torch to ONNX to TIDL for basic layers like add, mult and sub

Part Number: TDA4VM


Hi, 

There were guidelines in this link for writing specific modules in torch. These guidelines are conveyed for easier conversion from torchvision to onnx to TIDL. 
One of notes in the guidelines states to use layers from xnn like

xnn.layers.SubtractBlock
xnn.layers.MultBlock
xnn.layers.AddBlock
I have used the models for basic addition of tensors and multiplication. However, when I try to convert the onnx model to TIDL, I get the problem of unsuported layers. 
Unsupported (import) TIDL layer type --- 0 op type --- Sub
Supported TIDL layer type --- Flatten -- Flatten_1
Supported TIDL layer type --- Gemm -- Gemm_2
Unsupported (import) TIDL layer type --- 0 op type --- Tanh
Supported TIDL layer type --- Gemm -- Gemm_4
Unsupported (import) TIDL layer type --- 0 op type --- Tanh
Supported TIDL layer type --- Gemm -- Gemm_6
Supported TIDL layer type --- Sigmoid -- Sigmoid_7
Only elementwise numtiplication operator supported
Unsupported (import) TIDL layer type --- 0 op type --- Mul
Could I get some more information on how to exactly use the subtract, mult, add layers so that it converts to TIDL supported layers? Or are there no supported TIDL layers? 
Also one more question -> Does TIDL support divide layer?
Thank You
Niranjan
  • Hi Niranjan,

    What is the type of Sub and Mul operators in your model? Are they element-wise or channel-wise mul/sub?

    Latest SDK and edgeai_tidl_tools release for mul operator, supports element-wise operation and multiplication channel-wise broadcastable constant.

    We are yet to add support for sub operation which will be similar to current mul and are working on it

    Regards,

    Anand

  • Hi Anand, 

    I see that Add and Mul are supported from onnx to TIDL from the documentation here. The rough onnx model graph is here

    The output log for this model conversion is as follows 

    Unsupported (import) TIDL layer type for ONNX op type --- Sub
    Supported TIDL layer type --- Flatten -- Flatten_1
    Supported TIDL layer type --- Gemm -- Gemm_2
    Supported TIDL layer type --- Relu -- Relu_3
    Supported TIDL layer type --- Gemm -- Gemm_4
    Supported TIDL layer type --- Relu -- Relu_5
    Supported TIDL layer type --- Gemm -- Gemm_6
    Supported TIDL layer type --- Sigmoid -- Sigmoid_7
    Unsupported (TIDL check) TIDL layer type --- Mul
    Unsupported (TIDL check) TIDL layer type --- Add

    Preliminary subgraphs created = 1
    Final number of subgraphs created are : 1, - Offloaded Nodes - 7, Total Nodes - 10
    Layer type not supported by TIDL --- layer type - Sub, Node name -Sub_0
    ALLOWLISTING : ADD layer : The variable inputs of add layer must have 4 dimensions -- file info - tidl_import_common_model_check.cpp , TIDL_checkAddAndMulTensorProperties , 218
    ALLOWLISTING : ADD layer : The variable inputs of add layer must have 4 dimensions -- file info - tidl_import_common_model_check.cpp , TIDL_checkAddAndMulTensorProperties , 218
    Running runtimes graphviz - /resources/edgeai-tidl-tools-08_02_00_05/tidl_tools/tidl_graphVisualiser_runtimes.out ./recurse_net_onnx_artifacts//allowedNode.txt ./recurse_net_onnx_artifacts//tempDir/graphvizInfo.txt ./recurse_net_onnx_artifacts//tempDir/runtimes_visualization.svg
    *** In TIDL_createStateImportFunc ***
    Compute on node : TIDLExecutionProvider_TIDL_0_0
    0, Flatten, 1, 1, 13, 14
    1, Gemm, 3, 1, 14, 15
    2, Relu, 1, 1, 15, 16
    3, Gemm, 3, 1, 16, 17
    4, Relu, 1, 1, 17, 18
    5, Gemm, 3, 1, 18, 19
    6, Sigmoid, 1, 1, 19, 20
    Could you explain why the Mul and Add layers seem to be unsupported here? Do I have to do something special in torch for the proper conversion?
    Thank You
    Niranjan
  • Hi Niranjan,

    As you can see from the ALLOWLISTING check above, the layer is marked as unsupported because the input to the layer is expected to have 4 dimensions and it has only 2 in your model. If you make your input 4 dimensional, I think that should solve the issue.

    Regards,

    Anand

  • Hi Anand,

    Currently I was trying to do the following operation : 

    tensor(shape:(1,1))*tensor(shape:(1,2048))

    since the above tensor is not 4 dimensional, I have used the reshape. 

    tensor(shape:(1,1))*tensor(shape:(1,1,1,2048))

    However, I get the following error -> 

    DIM Error - For Tensor 4, Dim 1 is -1
    I believe the error is because of the reshape. 
    Could you let me know if simple multiplication is possible as in one element multiplied by a tensor of (1,x) shape? 
    Adding the complete log, for reference. 
    tidl_tools_path                                 = /resources/edgeai-tidl-tools-08_02_00_05/tidl_tools 
    artifacts_folder                                = ./recurse_net_onnx_artifacts/ 
    tidl_tensor_bits                                = 8 
    debug_level                                     = 3 
    num_tidl_subgraphs                              = 16 
    tidl_denylist                                   = MaxPool   
    tidl_calibration_accuracy_level                 = 7 
    tidl_calibration_options:num_frames_calibration = 3 
    tidl_calibration_options:bias_calibration_iterations = 1 
    power_of_2_quantization                         = 2 
    enable_high_resolution_optimization             = 0 
    pre_batchnorm_fold                              = 1 
    add_data_convert_ops                          = 0 
    output_feature_16bit_names_list                 =  
    m_params_16bit_names_list                       =  
    reserved_compile_constraints_flag               = 1601 
    ti_internal_reserved_1                          = 

     ****** WARNING : Network not identified as Object Detection network - Ignore if network is not OD *****

    Unsupported (import) TIDL layer type for ONNX op type --- Sub 
    Supported TIDL layer type ---            Gemm -- Gemm_1 
    Supported TIDL layer type ---            Relu -- Relu_2 
    Supported TIDL layer type ---            Gemm -- Gemm_3 
    Supported TIDL layer type ---            Relu -- Relu_4 
    Supported TIDL layer type ---            Gemm -- Gemm_5 
    Supported TIDL layer type ---         Sigmoid -- Sigmoid_6 
    Supported TIDL layer type ---         Reshape -- Reshape_8 
    Supported TIDL layer type ---         Reshape -- Reshape_10 
    Unsupported (TIDL check) TIDL layer type ---             Mul 
    Unsupported (TIDL check) TIDL layer type ---             Mul 
    Supported TIDL layer type ---             Add -- Add_13 
    Supported TIDL layer type ---         Reshape -- Reshape_15 

    Preliminary subgraphs created = 2 
    Final number of subgraphs created are : 2, - Offloaded Nodes - 10, Total Nodes - 13 
    Layer type not supported by TIDL --- layer type - Sub,  Node name -Sub_0  
    ALLOWLISTING : ADD layer : The variable inputs of add layer must have 4 dimensions  --  file info - tidl_import_common_model_check.cpp , TIDL_checkAddAndMulTensorProperties , 218  
    ALLOWLISTING : ADD layer : The variable inputs of add layer must have 4 dimensions  --  file info - tidl_import_common_model_check.cpp , TIDL_checkAddAndMulTensorProperties , 218  
    Running runtimes graphviz - /resources/edgeai-tidl-tools-08_02_00_05/tidl_tools/tidl_graphVisualiser_runtimes.out ./recurse_net_onnx_artifacts//allowedNode.txt ./recurse_net_onnx_artifacts//tempDir/graphvizInfo.txt ./recurse_net_onnx_artifacts//tempDir/runtimes_visualization.svg 
    *** In TIDL_createStateImportFunc *** 
    Compute on node : TIDLExecutionProvider_TIDL_0_0
      0,             Sub, 2, 1, 0, 9
      1,            Gemm, 3, 1, 9, 10
      2,            Relu, 1, 1, 10, 11
      3,            Gemm, 3, 1, 11, 12
      4,            Relu, 1, 1, 12, 13
      5,            Gemm, 3, 1, 13, 14
      6,         Reshape, 2, 1, 0, 17
      7,             Mul, 2, 1, 2, 21

    I[<onnxruntime.capi.onnxruntime_pybind11_state.NodeArg object at 0x7f4014a920d8>, <onnxruntime.capi.onnxruntime_pybind11_state.NodeArg object at 0x7f40141db0a0>, <onnxruntime.capi.onnxruntime_pybind11_state.NodeArg object at 0x7f40141db180>]
    came here second
    nput tensor name -  2 

    Input tensor name -  19 

    Input tensor name -  0 

    Input tensor name -  1 
    Output tensor name - 21 
    Output tensor name - 17 
    Output tensor name - 14 
    *** In TIDL_createStateImportFunc *** 
    Compute on node : TIDLExecutionProvider_TIDL_1_1
      0,             Add, 2, 1, 20, 22
      1,         Reshape, 2, 1, 22, 24

    Input tensor name -  20 

    Input tensor name -  21 
    Output tensor name - 24 
    In TIDL_onnxRtImportInit subgraph_name=141721
    Layer 0, subgraph id 141721, name=21
    Layer 1, subgraph id 141721, name=17
    Layer 2, subgraph id 141721, name=14
    Layer 3, subgraph id 141721, name=2
    Layer 4, subgraph id 141721, name=19
    Layer 5, subgraph id 141721, name=0
    Layer 6, subgraph id 141721, name=1
    In TIDL_runtimesOptimizeNet: LayerIndex = 15, dataIndex = 12 
    ****************************************************
    **   All the Input Tensor Dimensions has to be greater then Zero 
    **   DIM Error - For Tensor 4, Dim 1 is -1
    ****************************************************
    Thank You
    Niranjan
  • Hi Niranjan,

    Is it not possible to just set input to be a 4d tensor and export it to ONNX? That would be an easier fix, right?

    e.g. something like this in pytorch:

    input = torch.randn(1,3,224,224)  # have put some random values for dims as example
    torch.onnx.export(model, input, "model.onnx", verbose = False, opset_version=11, input_names=['input'], output_names=['output'])
    Regards,
    Anand
  • Hi Anand, 

    I am able to export the model to onnx. The problem comes when exporting from onnx to tidl format. 

    Are you suggesting to reshape the tensors from (1,2048) to (1,2048,1,1)? I believe two dimensional tensors are supported since most networks have fully connected layers or am I misunderstanding something? 

    Thank You

    Niranjan

  • Hi Niranjan,

    This issue is specific for Element wise layers, e.g . Add and Mul layers above. They will be expecting 4 dimensional inputs. This is not for fully connected layers.

    Will it be possible for you to share this particular network so I can run on my side? That can help in resolving the issue faster.

    Regards,

    Anand

  • Hi Anand, 

    I am sharing the small part of the network where there normally is the issue. I think you can use the code to create the onnx model which has issues converting to the TIDL format. The major problem as stated before seems to be the MUL operator. 

     

    import torch
    import torch.nn as nn
    
    import onnx
    import os
    
    class recurse_network(nn.Module):
    
        def __init__(self):
            super(recurse_network, self).__init__()
            self.fc1 = nn.Linear(512,1)
            self.sigmoid = nn.Sigmoid()
            
            self.flatten1 = torch.nn.Flatten(1)
            self.flatten2 = torch.nn.Flatten(1)
    
        def forward(self,input_val, prev_state, cumsum):
            diff = torch.subtract(input_val, prev_state)
            diff = self.flatten1(diff)
            diff = self.fc1(diff)
            imp = self.sigmoid(diff)
    
            input_mod = torch.multiply(imp, input_val)
            prev_state_mod = torch.multiply(cumsum, prev_state)
    
            next_state = torch.add(input_mod, prev_state_mod)
            next_state = torch.reshape(next_state, (1,512))
            next_state = self.flatten2(next_state)
            next_cum_sum = torch.add(imp, cumsum)
    
            return next_state, next_cum_sum 
    
    net = recurse_network()
    
    input_val = torch.randn( 1, 512)
    prev_state = torch.randn( 1, 512)
    cumsum = torch.randn(1,1)
    
    net.eval()
    out1 = net(input_val, prev_state, cumsum)
    print(out1)
    
    
    
    def write_onnx_model( model, save_path, name, input):
        filepath = os.path.join(save_path, name)
        model.eval()
        print ("onnx saved to file path ", filepath)
        opset_version = 11
        # 
        torch.onnx.export(model, input , f =filepath, export_params=True, verbose=False,
                          do_constant_folding=True, opset_version=opset_version)
        # infer shapes
        onnx.shape_inference.infer_shapes_path(filepath, filepath)
        # export torchscript model
        traced_model = torch.jit.trace(model, input)
        torch.jit.save(traced_model, os.path.splitext(filepath)[0]+'_model.pth')
        print('trochscript export done.')
    
    write_onnx_model(net, '.', 'ti_model.onnx', (input_val, prev_state, cumsum))

    The source code of tidl_onnxImport.cpp in tidl_j7_08_00_00_10 directory, 

    int32_t TIDL_onnxMapMulBaseParams(GraphProto&   onnGraph, int32_t i, sTIDL_LayerPC_t &layer)
    {
      if(onnGraph.node(i).input_size() != 2)
      {
        printf("Multiplication operator is supported for elementwise operation with only 2 inputs \n");
        return -1;
      }
      if(gParams.modelType == TIDL_IMPORT_MODEL_FORMAT_ONNX_RT)
      {
        std::vector<std::vector<int32_t>> inputShapes;
        std::vector<int32_t> nodeInputDims;
    
        for(int j = 0; j < onnGraph.node(i).input_size(); j++)
        {
          nodeInputDims = getNodeInputShape(onnGraph,  onnGraph.node(i).input(j), 0);
          inputShapes.push_back(nodeInputDims);
        }
    
        int n1 = inputShapes[0][0];
        int c1 = inputShapes[0][1];
        int h1 = inputShapes[0][2];
        int w1 = inputShapes[0][3];
        int n2 = inputShapes[1][0];
        int c2 = inputShapes[1][1];
        int h2 = inputShapes[1][2];
        int w2 = inputShapes[1][3];
    
        if((n1 == n2) && (c1 == c2) && (h1 == h2) && (w1 == w2))
        {
          layer.layerType = TIDL_EltWiseLayer;
          layer.layerParams.eltWiseParams.eltWiseType = TIDL_EltWiseProduct;
          layer.numInBufs = onnGraph.node(i).input_size();
        }
        else
        {
          printf("Only elementwise numtiplication operator supported \n");
          return -1;
        }
      }
      else
      {
        layer.layerType = TIDL_EltWiseLayer;
        layer.layerParams.eltWiseParams.eltWiseType = TIDL_EltWiseProduct;
        layer.numInBufs = onnGraph.node(i).input_size();
      }
    
      return 0;
    }
    I believe the MUL operator is for multiplication of two inputs with the same shape. Correct me if I am wrong. 
    Thank You
    Niranjan