318 lines
11 KiB
Python
318 lines
11 KiB
Python
# Copyright © 2020 Arm Ltd. All rights reserved.
|
|
# SPDX-License-Identifier: MIT
|
|
import os
|
|
import stat
|
|
|
|
import pytest
|
|
import pyarmnn as ann
|
|
|
|
def test_optimizer_options_default_values():
|
|
opt = ann.OptimizerOptions()
|
|
assert opt.m_ReduceFp32ToFp16 == False
|
|
assert opt.m_Debug == False
|
|
assert opt.m_ReduceFp32ToBf16 == False
|
|
assert opt.m_ImportEnabled == False
|
|
|
|
def test_optimizer_options_set_values1():
|
|
opt = ann.OptimizerOptions(True, True)
|
|
assert opt.m_ReduceFp32ToFp16 == True
|
|
assert opt.m_Debug == True
|
|
assert opt.m_ReduceFp32ToBf16 == False
|
|
assert opt.m_ImportEnabled == False
|
|
|
|
def test_optimizer_options_set_values2():
|
|
opt = ann.OptimizerOptions(False, False, True)
|
|
assert opt.m_ReduceFp32ToFp16 == False
|
|
assert opt.m_Debug == False
|
|
assert opt.m_ReduceFp32ToBf16 == True
|
|
assert opt.m_ImportEnabled == False
|
|
|
|
def test_optimizer_options_set_values3():
|
|
opt = ann.OptimizerOptions(False, False, True, True)
|
|
assert opt.m_ReduceFp32ToFp16 == False
|
|
assert opt.m_Debug == False
|
|
assert opt.m_ReduceFp32ToBf16 == True
|
|
assert opt.m_ImportEnabled == True
|
|
|
|
@pytest.fixture(scope="function")
|
|
def get_runtime(shared_data_folder, network_file):
|
|
parser= ann.ITfLiteParser()
|
|
preferred_backends = [ann.BackendId('CpuAcc'), ann.BackendId('CpuRef')]
|
|
network = parser.CreateNetworkFromBinaryFile(os.path.join(shared_data_folder, network_file))
|
|
options = ann.CreationOptions()
|
|
runtime = ann.IRuntime(options)
|
|
|
|
yield preferred_backends, network, runtime
|
|
|
|
|
|
@pytest.mark.parametrize("network_file",
|
|
[
|
|
'mock_model.tflite',
|
|
],
|
|
ids=['mock_model'])
|
|
def test_optimize_executes_successfully(network_file, get_runtime):
|
|
preferred_backends = [ann.BackendId('CpuRef')]
|
|
network = get_runtime[1]
|
|
runtime = get_runtime[2]
|
|
|
|
opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
|
|
|
|
assert len(messages) == 0, 'With only CpuRef, there should be no warnings irrelevant of architecture.'
|
|
assert opt_network
|
|
|
|
|
|
@pytest.mark.parametrize("network_file",
|
|
[
|
|
'mock_model.tflite',
|
|
],
|
|
ids=['mock_model'])
|
|
def test_optimize_owned_by_python(network_file, get_runtime):
|
|
preferred_backends = get_runtime[0]
|
|
network = get_runtime[1]
|
|
runtime = get_runtime[2]
|
|
|
|
opt_network, _ = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
|
|
assert opt_network.thisown
|
|
|
|
|
|
@pytest.mark.aarch64
|
|
@pytest.mark.parametrize("network_file",
|
|
[
|
|
'mock_model.tflite'
|
|
],
|
|
ids=['mock_model'])
|
|
def test_optimize_executes_successfully_for_neon_backend_only(network_file, get_runtime):
|
|
preferred_backends = [ann.BackendId('CpuAcc')]
|
|
network = get_runtime[1]
|
|
runtime = get_runtime[2]
|
|
|
|
opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
|
|
assert 0 == len(messages)
|
|
assert opt_network
|
|
|
|
|
|
@pytest.mark.parametrize("network_file",
|
|
[
|
|
'mock_model.tflite'
|
|
],
|
|
ids=['mock_model'])
|
|
def test_optimize_fails_for_invalid_backends(network_file, get_runtime):
|
|
invalid_backends = [ann.BackendId('Unknown')]
|
|
network = get_runtime[1]
|
|
runtime = get_runtime[2]
|
|
|
|
with pytest.raises(RuntimeError) as err:
|
|
ann.Optimize(network, invalid_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
|
|
|
|
expected_error_message = "None of the preferred backends [Unknown ] are supported."
|
|
assert expected_error_message in str(err.value)
|
|
|
|
|
|
@pytest.mark.parametrize("network_file",
|
|
[
|
|
'mock_model.tflite'
|
|
],
|
|
ids=['mock_model'])
|
|
def test_optimize_fails_for_no_backends_specified(network_file, get_runtime):
|
|
empty_backends = []
|
|
network = get_runtime[1]
|
|
runtime = get_runtime[2]
|
|
|
|
with pytest.raises(RuntimeError) as err:
|
|
ann.Optimize(network, empty_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
|
|
|
|
expected_error_message = "Invoked Optimize with no backends specified"
|
|
assert expected_error_message in str(err.value)
|
|
|
|
|
|
@pytest.mark.parametrize("network_file",
|
|
[
|
|
'mock_model.tflite'
|
|
],
|
|
ids=['mock_model'])
|
|
def test_serialize_to_dot(network_file, get_runtime, tmpdir):
|
|
preferred_backends = get_runtime[0]
|
|
network = get_runtime[1]
|
|
runtime = get_runtime[2]
|
|
opt_network, _ = ann.Optimize(network, preferred_backends,
|
|
runtime.GetDeviceSpec(), ann.OptimizerOptions())
|
|
dot_file_path = os.path.join(tmpdir, 'mock_model.dot')
|
|
"""Check that serialized file does not exist at the start, gets created after SerializeToDot and is not empty"""
|
|
assert not os.path.exists(dot_file_path)
|
|
opt_network.SerializeToDot(dot_file_path)
|
|
|
|
assert os.path.exists(dot_file_path)
|
|
|
|
with open(dot_file_path) as res_file:
|
|
expected_data = res_file.read()
|
|
assert len(expected_data) > 1
|
|
assert '[label=< [1,28,28,1] >]' in expected_data
|
|
|
|
|
|
@pytest.mark.x86_64
|
|
@pytest.mark.parametrize("network_file",
|
|
[
|
|
'mock_model.tflite'
|
|
],
|
|
ids=['mock_model'])
|
|
def test_serialize_to_dot_mode_readonly(network_file, get_runtime, tmpdir):
|
|
preferred_backends = get_runtime[0]
|
|
network = get_runtime[1]
|
|
runtime = get_runtime[2]
|
|
opt_network, _ = ann.Optimize(network, preferred_backends,
|
|
runtime.GetDeviceSpec(), ann.OptimizerOptions())
|
|
"""Create file, write to it and change mode to read-only"""
|
|
dot_file_path = os.path.join(tmpdir, 'mock_model.dot')
|
|
f = open(dot_file_path, "w+")
|
|
f.write("test")
|
|
f.close()
|
|
os.chmod(dot_file_path, stat.S_IREAD)
|
|
assert os.path.exists(dot_file_path)
|
|
|
|
with pytest.raises(RuntimeError) as err:
|
|
opt_network.SerializeToDot(dot_file_path)
|
|
|
|
expected_error_message = "Failed to open dot file"
|
|
assert expected_error_message in str(err.value)
|
|
|
|
|
|
@pytest.mark.parametrize("method", [
|
|
'AddActivationLayer',
|
|
'AddAdditionLayer',
|
|
'AddArgMinMaxLayer',
|
|
'AddBatchNormalizationLayer',
|
|
'AddBatchToSpaceNdLayer',
|
|
'AddComparisonLayer',
|
|
'AddConcatLayer',
|
|
'AddConstantLayer',
|
|
'AddConvolution2dLayer',
|
|
'AddDepthToSpaceLayer',
|
|
'AddDepthwiseConvolution2dLayer',
|
|
'AddDequantizeLayer',
|
|
'AddDetectionPostProcessLayer',
|
|
'AddDivisionLayer',
|
|
'AddElementwiseUnaryLayer',
|
|
'AddFloorLayer',
|
|
'AddFillLayer',
|
|
'AddFullyConnectedLayer',
|
|
'AddGatherLayer',
|
|
'AddInputLayer',
|
|
'AddInstanceNormalizationLayer',
|
|
'AddLogSoftmaxLayer',
|
|
'AddL2NormalizationLayer',
|
|
'AddLstmLayer',
|
|
'AddMaximumLayer',
|
|
'AddMeanLayer',
|
|
'AddMergeLayer',
|
|
'AddMinimumLayer',
|
|
'AddMultiplicationLayer',
|
|
'AddNormalizationLayer',
|
|
'AddOutputLayer',
|
|
'AddPadLayer',
|
|
'AddPermuteLayer',
|
|
'AddPooling2dLayer',
|
|
'AddPreluLayer',
|
|
'AddQuantizeLayer',
|
|
'AddQuantizedLstmLayer',
|
|
'AddRankLayer',
|
|
'AddReshapeLayer',
|
|
'AddResizeLayer',
|
|
'AddSliceLayer',
|
|
'AddSoftmaxLayer',
|
|
'AddSpaceToBatchNdLayer',
|
|
'AddSpaceToDepthLayer',
|
|
'AddSplitterLayer',
|
|
'AddStackLayer',
|
|
'AddStandInLayer',
|
|
'AddStridedSliceLayer',
|
|
'AddSubtractionLayer',
|
|
'AddSwitchLayer',
|
|
'AddTransposeConvolution2dLayer'
|
|
])
|
|
def test_network_method_exists(method):
|
|
assert getattr(ann.INetwork, method, None)
|
|
|
|
|
|
def test_fullyconnected_layer_optional_none():
|
|
net = ann.INetwork()
|
|
layer = net.AddFullyConnectedLayer(fullyConnectedDescriptor=ann.FullyConnectedDescriptor(),
|
|
weights=ann.ConstTensor())
|
|
|
|
assert layer
|
|
|
|
|
|
def test_fullyconnected_layer_optional_provided():
|
|
net = ann.INetwork()
|
|
layer = net.AddFullyConnectedLayer(fullyConnectedDescriptor=ann.FullyConnectedDescriptor(),
|
|
weights=ann.ConstTensor(),
|
|
biases=ann.ConstTensor())
|
|
|
|
assert layer
|
|
|
|
|
|
def test_fullyconnected_layer_all_args():
|
|
net = ann.INetwork()
|
|
layer = net.AddFullyConnectedLayer(fullyConnectedDescriptor=ann.FullyConnectedDescriptor(),
|
|
weights=ann.ConstTensor(),
|
|
biases=ann.ConstTensor(),
|
|
name='NAME1')
|
|
|
|
assert layer
|
|
assert 'NAME1' == layer.GetName()
|
|
|
|
|
|
def test_DepthwiseConvolution2d_layer_optional_none():
|
|
net = ann.INetwork()
|
|
layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
|
|
weights=ann.ConstTensor())
|
|
|
|
assert layer
|
|
|
|
|
|
def test_DepthwiseConvolution2d_layer_optional_provided():
|
|
net = ann.INetwork()
|
|
layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
|
|
weights=ann.ConstTensor(),
|
|
biases=ann.ConstTensor())
|
|
|
|
assert layer
|
|
|
|
|
|
def test_DepthwiseConvolution2d_layer_all_args():
|
|
net = ann.INetwork()
|
|
layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
|
|
weights=ann.ConstTensor(),
|
|
biases=ann.ConstTensor(),
|
|
name='NAME1')
|
|
|
|
assert layer
|
|
assert 'NAME1' == layer.GetName()
|
|
|
|
|
|
def test_Convolution2d_layer_optional_none():
|
|
net = ann.INetwork()
|
|
layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
|
|
weights=ann.ConstTensor())
|
|
|
|
assert layer
|
|
|
|
|
|
def test_Convolution2d_layer_optional_provided():
|
|
net = ann.INetwork()
|
|
layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
|
|
weights=ann.ConstTensor(),
|
|
biases=ann.ConstTensor())
|
|
|
|
assert layer
|
|
|
|
|
|
def test_Convolution2d_layer_all_args():
|
|
net = ann.INetwork()
|
|
layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
|
|
weights=ann.ConstTensor(),
|
|
biases=ann.ConstTensor(),
|
|
name='NAME1')
|
|
|
|
assert layer
|
|
assert 'NAME1' == layer.GetName()
|