NNAPI conversion for a CNN - node kind is not in ADDER_MAP

username: serviceberry3
cooked: <p>I’m trying to use the new torch.backends._nnapi.prepare.convert_model_to_nnapi() function to prepare a PyTorch CNN model for NNAPI on an Android device. I’m basically following <a href="https://pytorch.org/tutorials/prototype/nnapi_mobilenetv2.html" rel="noopener nofollow ugc">this</a> tutorial. Here’s my code:</p>
<pre><code class="lang-auto">#Prepare the trained model for NNAPI on Android device
import sys
import os
import torch
import torch.utils.bundled_inputs
import torch.utils.mobile_optimizer
import torch.backends._nnapi.prepare
import torchvision.models.quantization.mobilenet
from pathlib import Path

#import a function from a different module that returns the model in eval mode, loading the state dict from a checkpoint file (pretrained)
from common.model import trace_model


# This script supports 3 modes of quantization:
# - "none": Fully floating-point model.
# - "core": Quantize the core of the model, but wrap it a
#    quantizer/dequantizer pair, so the interface uses floating point.
# - "full": Quantize the model, and use quantized tensors
#   for input and output.
#
# "none" maintains maximum accuracy
# "core" sacrifices some accuracy for performance,
# but maintains the same interface.
# "full" maximized performance (with the same accuracy as "core"),
# but requires the application to use quantized tensors.
#
# There is a fourth option, not supported by this script,
# where we include the quant/dequant steps as NNAPI operators.
def make_mymodel_nnapi(output_dir_path, quantize_mode):
    quantize_core, quantize_iface = {
        "none": (False, False),
        "core": (True, False),
        "full": (True, True),
    }[quantize_mode]

#get the model. Ignore layers
    model, layers = trace_model() 

#Commented this section out because model I'm using doesn't have fuse_model() fxn.
    # Fuse BatchNorm operators in the floating point model.
    # (Quantized models already have this done.)
    # Remove dropout for this inference-only use case.
    #if not quantize_core:
    #    model.fuse_model()

    
    #assert type(model.classifier[0]) == torch.nn.Dropout

    #model.classifier[0] = torch.nn.Identity()

#create some input based on my CNN's shape
    input_float = torch.zeros(2, 272, 17, 2)
    input_tensor = input_float

    
    # If we're doing a quantized model, we need to trace only the quantized core.
    # So capture the quantizer and dequantizer, use them to prepare the input,
    # and replace them with identity modules so we can trace without them.
    if quantize_core:
        quantizer = model.quant
        dequantizer = model.dequant
        model.quant = torch.nn.Identity()
        model.dequant = torch.nn.Identity()
        input_tensor = quantizer(input_float)


    
    # Many NNAPI backends prefer NHWC tensors, so convert our input to channels_last,
    # and set the "nnapi_nhwc" attribute for the converter.
    input_tensor = input_tensor.contiguous(memory_format=torch.channels_last)
    input_tensor.nnapi_nhwc = True

    # Trace the model.  NNAPI conversion only works with TorchScript models,
    # and traced models are more likely to convert successfully than scripted.
    with torch.no_grad():
        traced = torch.jit.trace(model, input_tensor)
       

#ERROR IN THIS FUNCTION
#Prepare model for NNAPI
    nnapi_model = torch.backends._nnapi.prepare.convert_model_to_nnapi(traced, input_tensor)




if __name__ == "__main__":
    for quantize_mode in ["none", "core", "full"]:
        make_mymodel_nnapi(Path(os.environ["HOME"]) / "mobilenetv2-nnapi", quantize_mode)
</code></pre>
<p>What I get is an error in the convert_model_to_nnapi() function:</p>
<pre><code class="lang-auto">Traceback (most recent call last):
  File "trace_model_nnapi.py", line 131, in &lt;module&gt;
    make_mymodel_nnapi(Path(os.environ["HOME"]) / "mobilenetv2-nnapi", quantize_mode)
  File "trace_model_nnapi.py", line 89, in make_mymodel_nnapi
    nnapi_model = torch.backends._nnapi.prepare.convert_model_to_nnapi(traced, input_tensor)
  File "/home/nodog/.local/lib/python3.8/site-packages/torch/backends/_nnapi/prepare.py", line 169, in convert_model_to_nnapi
    ser_model, used_weights, inp_mem_fmts, out_mem_fmts = serialize_model(model, inputs)
  File "/home/nodog/.local/lib/python3.8/site-packages/torch/backends/_nnapi/serializer.py", line 1363, in serialize_model
    return _NnapiSerializer(config).serialize_model(module, inputs)
  File "/home/nodog/.local/lib/python3.8/site-packages/torch/backends/_nnapi/serializer.py", line 520, in serialize_model
    self.add_node(node)
  File "/home/nodog/.local/lib/python3.8/site-packages/torch/backends/_nnapi/serializer.py", line 641, in add_node
    raise Exception("Unsupported node kind (%r) in node %r" % (node.kind(), node))
Exception: Unsupported node kind ('aten::contiguous') in node %x.2 : Tensor = aten::contiguous(%x.1, %39) # /home/nodog/docs/asp/mymodel/common/model.py:267:0

</code></pre>
<p>And if I comment out the “Many NNAPI backends prefer NHWC tensors” part of the code:</p>
<pre><code class="lang-auto">Traceback (most recent call last):
  File "trace_model_nnapi.py", line 131, in &lt;module&gt;
    make_mymodel_nnapi(Path(os.environ["HOME"]) / "mobilenetv2-nnapi", quantize_mode)
  File "trace_model_nnapi.py", line 89, in make_mynmodel_nnapi
    nnapi_model = torch.backends._nnapi.prepare.convert_model_to_nnapi(traced, input_tensor)
  File "/home/nodog/.local/lib/python3.8/site-packages/torch/backends/_nnapi/prepare.py", line 169, in convert_model_to_nnapi
    ser_model, used_weights, inp_mem_fmts, out_mem_fmts = serialize_model(model, inputs)
  File "/home/nodog/.local/lib/python3.8/site-packages/torch/backends/_nnapi/serializer.py", line 1363, in serialize_model
    return _NnapiSerializer(config).serialize_model(module, inputs)
  File "/home/nodog/.local/lib/python3.8/site-packages/torch/backends/_nnapi/serializer.py", line 520, in serialize_model
    self.add_node(node)
  File "/home/nodog/.local/lib/python3.8/site-packages/torch/backends/_nnapi/serializer.py", line 641, in add_node
    raise Exception("Unsupported node kind (%r) in node %r" % (node.kind(), node))
Exception: Unsupported node kind ('aten::size') in node %40 : int = aten::size(%x.1, %39) # /home/nodog/docs/asp/mymodel/common/model.py:269:0

</code></pre>
<p>It appears that ‘aten::size’ and ‘aten::contiguous’ are not included in ADDER_MAP (what looks to be a list of node types) in serializer.py. Does anyone know if I’m doing something wrong, or if some functionality just hasn’t been added to the NNAPI system yet?<br>
By the way, the CNN model I use has Conv1d, Batchnorm, Dropout, and Relu layers.</p>
<p>Thanks!</p>

username: ekremcet
cooked: <p>Some layers are not supported by NNAPI system yet. You can see the list of supported ops here:</p><aside class="onebox githubblob">
  <header class="source">
      <a href="https://github.com/pytorch/pytorch/blob/master/torch/backends/_nnapi/serializer.py#L585-L636" target="_blank" rel="noopener nofollow ugc">github.com</a>
  </header>
  <article class="onebox-body">
    <h4><a href="https://github.com/pytorch/pytorch/blob/master/torch/backends/_nnapi/serializer.py#L585-L636" target="_blank" rel="noopener nofollow ugc">pytorch/pytorch/blob/master/torch/backends/_nnapi/serializer.py#L585-L636</a></h4>
<pre class="onebox"><code class="lang-py"><ol class="start lines" start="585" style="counter-reset: li-counter 584 ;">
<li>ADDER_MAP = {</li><li>    "prim::GetAttr": lambda self, node:</li><li>        self.add_getattr(node),</li><li>    "prim::Constant": lambda self, node:</li><li>        self.add_constant_node(node),</li><li>    "prim::ListConstruct": lambda self, node:</li><li>        self.add_list_construct(node),</li><li>    "prim::TupleConstruct": lambda self, node:</li><li>        self.add_tuple_construct(node),</li><li>    "aten::reshape": lambda self, node:</li><li>        self.add_reshape(node),</li><li>    "aten::size": lambda self, node:</li><li>        self.add_size(node),</li><li>    "aten::quantize_per_tensor": lambda self, node:</li><li>        self.add_quantize(node),</li><li>    "aten::dequantize": lambda self, node:</li><li>        self.add_dequantize(node),</li><li>    "aten::add": lambda self, node:</li><li>        self.add_add_sub_op(node, NNAPI_OperationCode.ADD, NNAPI_FuseCode.FUSED_NONE),</li><li>    "aten::sub": lambda self, node:</li>
</ol></code></pre>

  This file has been truncated. <a href="https://github.com/pytorch/pytorch/blob/master/torch/backends/_nnapi/serializer.py#L585-L636" target="_blank" rel="noopener nofollow ugc">show original</a>

  </article>
  <div class="onebox-metadata">
    
    
  </div>
  <div style="clear: both"></div>
</aside>