mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-07 00:21:07 +01:00
Summary: Pull Request resolved: https://github.com/pytorch/pytorch/pull/62272 Added Android NNAPI delegate implementation of runtime initialization (compilation) and execution. The delegate's preprocess step was [previously implemented](https://github.com/pytorch/pytorch/pull/62225). Now, the reset of the delegate, which implements client-side execution, is added. **nnapi_backend_lib.cpp**: Implementation of delegate's compile and execute. `execute()` is essentially a C++ implementation of [`NnapiModule`](https://github.com/pytorch/pytorch/blob/master/torch/backends/_nnapi/prepare.py), which wraps an NNAPI Compilation and handles preparation of weights, inputs, and outputs. - Any steps that can be done before execution are moved to `compile()`. - `init()` cannot be moved to `compile()` because it requires real inputs for dynamic shaping. - `shape_compute_module` cannot currently be deserialized in `compile()`, since mobile::Module has no IValue conversion. - Processed arguments that are modified by `init()` must be kept as member variables. Any other processed arguments are passed through a dictionary, `handles`. **nnapi_bind.cpp & nnapi_bind.h**: Created a header file for `nnapi_bind.cpp`, so that it's NnapiCompilation class can be used by `nnapi_backend_lib.cpp`. **test_backend_nnapi.py**: Enabled execution testing. ghstack-source-id: 135432844 Test Plan: Imported from OSS Tested on devserver. 1. Load and unpack a special devserver build of NNAPI: `jf download GICWmAAzUR0eo20TAPasVts8ObhobsIXAAAz --file "nnapi-host-linux.tar.xz"` 2. `export LIBNEURALNETWORKS_PATH=/path/to/libneuralnetworks.so` 3. Run unittests: `python test/test_jit.py TestNnapiBackend` and `python test/test_nnapi.py` TODO: test with lite interpreter runtime Reviewed By: raziel, iseeyuan Differential Revision: D29944873 fbshipit-source-id: 48967d873e79ef2cce9bcba2aeea3c52f7a18c07
114 lines
5.0 KiB
Python
114 lines
5.0 KiB
Python
import os
|
|
import sys
|
|
import unittest
|
|
|
|
import torch
|
|
import torch._C
|
|
from pathlib import Path
|
|
from test_nnapi import TestNNAPI
|
|
from torch.testing._internal.common_utils import TEST_WITH_ASAN
|
|
|
|
# Make the helper files in test/ importable
|
|
pytorch_test_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
|
sys.path.append(pytorch_test_dir)
|
|
|
|
if __name__ == "__main__":
|
|
raise RuntimeError(
|
|
"This test file is not meant to be run directly, use:\n\n"
|
|
"\tpython test/test_jit.py TESTNAME\n\n"
|
|
"instead."
|
|
)
|
|
|
|
"""
|
|
Unit Tests for Nnapi backend with delegate
|
|
Inherits most tests from TestNNAPI, which loads Android NNAPI models
|
|
without the delegate API.
|
|
"""
|
|
# First skip is needed for IS_WINDOWS or IS_MACOS to skip the tests.
|
|
# Second skip is because ASAN is currently causing an error.
|
|
# It is still unclear how to resolve this. T95764916
|
|
torch_root = Path(__file__).resolve().parent.parent.parent
|
|
lib_path = torch_root / 'build' / 'lib' / 'libnnapi_backend.so'
|
|
@unittest.skipIf(not os.path.exists(lib_path),
|
|
"Skipping the test as libnnapi_backend.so was not found")
|
|
@unittest.skipIf(TEST_WITH_ASAN, "Unresolved bug with ASAN")
|
|
class TestNnapiBackend(TestNNAPI):
|
|
def setUp(self):
|
|
super().setUp()
|
|
|
|
# Save default dtype
|
|
module = torch.nn.PReLU()
|
|
self.default_dtype = module.weight.dtype
|
|
# Change dtype to float32 (since a different unit test changed dtype to float64,
|
|
# which is not supported by the Android NNAPI delegate)
|
|
# Float32 should typically be the default in other files.
|
|
torch.set_default_dtype(torch.float32)
|
|
|
|
# Load nnapi delegate library
|
|
torch.ops.load_library(str(lib_path))
|
|
|
|
# Override
|
|
def call_lowering_to_nnapi(self, traced_module, args):
|
|
compile_spec = {"forward": {"inputs": args}}
|
|
return torch._C._jit_to_backend("nnapi", traced_module, compile_spec)
|
|
|
|
def test_tensor_input(self):
|
|
# Lower a simple module
|
|
args = torch.tensor([[1.0, -1.0, 2.0, -2.0]]).unsqueeze(-1).unsqueeze(-1)
|
|
module = torch.nn.PReLU()
|
|
traced = torch.jit.trace(module, args)
|
|
|
|
# Argument input is a single Tensor
|
|
self.call_lowering_to_nnapi(traced, args)
|
|
# Argument input is a Tensor in a list
|
|
self.call_lowering_to_nnapi(traced, [args])
|
|
|
|
# Test exceptions for incorrect compile specs
|
|
def test_compile_spec_santiy(self):
|
|
args = torch.tensor([[1.0, -1.0, 2.0, -2.0]]).unsqueeze(-1).unsqueeze(-1)
|
|
module = torch.nn.PReLU()
|
|
traced = torch.jit.trace(module, args)
|
|
|
|
errorMsgTail = r"""
|
|
method_compile_spec should contain a Tensor or Tensor List which bundles input parameters: shape, dtype, quantization, and dimorder.
|
|
For input shapes, use 0 for run/load time flexible input.
|
|
method_compile_spec must use the following format:
|
|
{"forward": {"inputs": at::Tensor}} OR {"forward": {"inputs": c10::List<at::Tensor>}}"""
|
|
|
|
# No forward key
|
|
compile_spec = {"backward": {"inputs": args}}
|
|
with self.assertRaisesRegex(RuntimeError, "method_compile_spec does not contain the \"forward\" key." + errorMsgTail):
|
|
torch._C._jit_to_backend("nnapi", traced, compile_spec)
|
|
|
|
# No dictionary under the forward key
|
|
compile_spec = {"forward": 1}
|
|
with self.assertRaisesRegex(RuntimeError,
|
|
"method_compile_spec does not contain a dictionary with an \"inputs\" key, "
|
|
"under it's \"forward\" key."
|
|
+ errorMsgTail):
|
|
torch._C._jit_to_backend("nnapi", traced, compile_spec)
|
|
|
|
# No inputs key (in the dictionary under the forward key)
|
|
compile_spec = {"forward": {"not inputs": args}}
|
|
with self.assertRaisesRegex(RuntimeError,
|
|
"method_compile_spec does not contain a dictionary with an \"inputs\" key, "
|
|
"under it's \"forward\" key."
|
|
+ errorMsgTail):
|
|
torch._C._jit_to_backend("nnapi", traced, compile_spec)
|
|
|
|
# No Tensor or TensorList under the inputs key
|
|
compile_spec = {"forward": {"inputs": 1}}
|
|
with self.assertRaisesRegex(RuntimeError,
|
|
"method_compile_spec does not contain either a Tensor or TensorList, under it's \"inputs\" key."
|
|
+ errorMsgTail):
|
|
torch._C._jit_to_backend("nnapi", traced, compile_spec)
|
|
compile_spec = {"forward": {"inputs": [1]}}
|
|
with self.assertRaisesRegex(RuntimeError,
|
|
"method_compile_spec does not contain either a Tensor or TensorList, under it's \"inputs\" key."
|
|
+ errorMsgTail):
|
|
torch._C._jit_to_backend("nnapi", traced, compile_spec)
|
|
|
|
def tearDown(self):
|
|
# Change dtype back to default (Otherwise, other unit tests will complain)
|
|
torch.set_default_dtype(self.default_dtype)
|