xref: /aosp_15_r20/external/armnn/delegate/python/test/test_external_delegate.py (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1# Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
2# SPDX-License-Identifier: MIT
3
4import numpy as np
5import pytest
6import tflite_runtime.interpreter as tflite
7import os
8from utils import run_mock_model, run_inference, compare_outputs
9
10def test_external_delegate_unknown_options(delegate_dir):
11    print(delegate_dir)
12    with pytest.raises(ValueError):
13        tflite.load_delegate(
14            delegate_dir,
15            options={"wrong": "wrong"})
16
17def test_external_delegate_options_multiple_backends(delegate_dir):
18    tflite.load_delegate(
19        delegate_dir,
20        options={"backends": "GpuAcc,CpuAcc,CpuRef,Unknown"})
21
22
23@pytest.mark.GpuAccTest
24def test_external_delegate_options_gpu_tuning(delegate_dir, test_data_folder, tmp_path):
25
26    tuning_file = os.path.join(str(tmp_path), "test_gpu.tuning")
27    # cleanup previous test run if necessary
28    if os.path.exists(tuning_file):
29        os.remove(tuning_file)
30
31    # with tuning level 2 a tuning file should be created
32    armnn_delegate = tflite.load_delegate(
33        delegate_dir,
34        options={
35            "backends": "GpuAcc",
36            "gpu-tuning-level": "2",
37            "gpu-tuning-file": tuning_file,
38            "logging-severity": "info"})
39
40    run_mock_model(armnn_delegate, test_data_folder)
41
42    # destroy delegate, otherwise tuning file won't be written to file
43    armnn_delegate.__del__()
44    assert (os.path.exists(tuning_file))
45
46    # if no tuning level is provided it defaults to 0 which means it will use the tuning parameters from a tuning
47    # file if one is provided
48    armnn_delegate2 = tflite.load_delegate(
49        delegate_dir,
50        options={
51            "backends": "GpuAcc",
52            "gpu-tuning-file": tuning_file,
53            "logging-severity": "info"})
54
55    run_mock_model(armnn_delegate2, test_data_folder)
56
57    # cleanup
58    os.remove(tuning_file)
59
60@pytest.mark.GpuAccTest
61def test_external_delegate_options_gpu_cached_network(delegate_dir, test_data_folder, tmp_path):
62
63    binary_file = os.path.join(str(tmp_path), "test_binary.bin")
64    # cleanup previous test run if necessary
65    if os.path.exists(binary_file):
66        os.remove(binary_file)
67
68    # Create blank binary file to write to.
69    open(binary_file, "a").close()
70    assert (os.path.exists(binary_file))
71    assert (os.stat(binary_file).st_size == 0)
72
73    # Run inference to save cached network.
74    armnn_delegate = tflite.load_delegate(
75        delegate_dir,
76        options={
77            "backends": "GpuAcc",
78            "save-cached-network": "1",
79            "cached-network-filepath": binary_file,
80            "logging-severity": "info"})
81
82    run_mock_model(armnn_delegate, test_data_folder)
83
84    # destroy delegate and check if file has been saved.
85    armnn_delegate.__del__()
86    assert (os.stat(binary_file).st_size != 0)
87
88    # Create second delegate to load in binary file created.
89    armnn_delegate2 = tflite.load_delegate(
90        delegate_dir,
91        options={
92            "backends": "GpuAcc",
93            "cached-network-filepath": binary_file,
94            "logging-severity": "info"})
95
96    run_mock_model(armnn_delegate2, test_data_folder)
97
98    # cleanup
99    os.remove(binary_file)
100
101@pytest.mark.GpuAccTest
102def test_external_delegate_gpu_fastmath(delegate_dir, test_data_folder):
103    # create armnn delegate with enable-fast-math
104    # fast-math is only enabled on Conv2d layer, so use conv2d model.
105    armnn_delegate = tflite.load_delegate(delegate_dir, options = {"backends": "GpuAcc",
106                                                                   "enable-fast-math": "1",
107                                                                   "logging-severity": "info"})
108
109    model_file_name = "conv2d.tflite"
110
111    inputShape = [ 1, 5, 5, 1 ]
112    outputShape = [ 1, 3, 3, 1 ]
113
114    inputValues = [ 1, 5, 2, 3, 5,
115                    8, 7, 3, 6, 3,
116                    3, 3, 9, 1, 9,
117                    4, 1, 8, 1, 3,
118                    6, 8, 1, 9, 2 ]
119
120    expectedResult = [ 28, 38, 29,
121                       96, 104, 53,
122                       31, 55, 24 ]
123
124    input = np.array(inputValues, dtype=np.float32).reshape(inputShape)
125    expected_output = np.array(expectedResult, dtype=np.float32).reshape(outputShape)
126
127    # run the inference
128    armnn_outputs = run_inference(test_data_folder, model_file_name, [input], [armnn_delegate])
129
130    # check results
131    compare_outputs(armnn_outputs, [expected_output])
132
133@pytest.mark.CpuAccTest
134def test_external_delegate_cpu_options(delegate_dir, test_data_folder):
135    # create armnn delegate with enable-fast-math and number-of-threads options
136    # fast-math is only enabled on Conv2d layer, so use conv2d model.
137    armnn_delegate = tflite.load_delegate(delegate_dir, options = {"backends": "CpuAcc",
138                                                                   "enable-fast-math": "1",
139                                                                   "number-of-threads": "4",
140                                                                   "logging-severity": "info"})
141
142    model_file_name = "conv2d.tflite"
143
144    inputShape = [ 1, 5, 5, 1 ]
145    outputShape = [ 1, 3, 3, 1 ]
146
147    inputValues = [ 1, 5, 2, 3, 5,
148                    8, 7, 3, 6, 3,
149                    3, 3, 9, 1, 9,
150                    4, 1, 8, 1, 3,
151                    6, 8, 1, 9, 2 ]
152
153    expectedResult = [ 28, 38, 29,
154                       96, 104, 53,
155                       31, 55, 24 ]
156
157    input = np.array(inputValues, dtype=np.float32).reshape(inputShape)
158    expected_output = np.array(expectedResult, dtype=np.float32).reshape(outputShape)
159
160    # run the inference
161    armnn_outputs = run_inference(test_data_folder, model_file_name, [input], [armnn_delegate])
162
163    # check results
164    compare_outputs(armnn_outputs, [expected_output])
165
166def test_external_delegate_options_wrong_logging_level(delegate_dir):
167    with pytest.raises(ValueError):
168        tflite.load_delegate(
169            delegate_dir,
170            options={"logging-severity": "wrong"})
171
172def test_external_delegate_options_debug(capfd, delegate_dir, test_data_folder):
173    # create armnn delegate with debug option
174    armnn_delegate = tflite.load_delegate(delegate_dir, options = {"backends": "CpuRef",
175                                                                   "debug-data": "1"})
176
177    model_file_name = "fp32_model.tflite"
178
179    tensor_shape = [1, 2, 2, 1]
180
181    input0 = np.array([1, 2, 3, 4], dtype=np.float32).reshape(tensor_shape)
182    input1 = np.array([2, 2, 3, 4], dtype=np.float32).reshape(tensor_shape)
183    inputs = [input0, input0, input1]
184    expected_output = np.array([1, 2, 2, 2], dtype=np.float32).reshape(tensor_shape)
185
186    # run the inference
187    armnn_outputs = run_inference(test_data_folder, model_file_name, inputs, [armnn_delegate])
188
189    # check results
190    compare_outputs(armnn_outputs, [expected_output])
191
192    captured = capfd.readouterr()
193    assert "layerGuid" in captured.out
194
195
196def test_external_delegate_options_fp32_to_fp16(capfd, delegate_dir, test_data_folder):
197    # create armnn delegate with reduce-fp32-to-fp16 option
198    armnn_delegate = tflite.load_delegate(delegate_dir, options = {"backends": "CpuRef",
199                                                                   "debug-data": "1",
200                                                                   "reduce-fp32-to-fp16": "1"})
201
202    model_file_name = "fp32_model.tflite"
203
204    tensor_shape = [1, 2, 2, 1]
205
206    input0 = np.array([1, 2, 3, 4], dtype=np.float32).reshape(tensor_shape)
207    input1 = np.array([2, 2, 3, 4], dtype=np.float32).reshape(tensor_shape)
208    inputs = [input0, input0, input1]
209    expected_output = np.array([1, 2, 2, 2], dtype=np.float32).reshape(tensor_shape)
210
211    # run the inference
212    armnn_outputs = run_inference(test_data_folder, model_file_name, inputs, [armnn_delegate])
213
214    # check results
215    compare_outputs(armnn_outputs, [expected_output])
216
217    captured = capfd.readouterr()
218    assert "convert_fp32_to_fp16" in captured.out
219    assert "convert_fp16_to_fp32" in captured.out
220
221def test_external_delegate_options_memory_import(delegate_dir, test_data_folder):
222    # create armnn delegate with memory-import option
223    armnn_delegate = tflite.load_delegate(delegate_dir, options = {"backends": "CpuAcc,CpuRef",
224                                                                   "memory-import": "1"})
225
226    model_file_name = "fallback_model.tflite"
227
228    tensor_shape = [1, 2, 2, 1]
229
230    input0 = np.array([1, 2, 3, 4], dtype=np.uint8).reshape(tensor_shape)
231    input1 = np.array([2, 2, 3, 4], dtype=np.uint8).reshape(tensor_shape)
232    inputs = [input0, input0, input1]
233    expected_output = np.array([1, 2, 2, 2], dtype=np.uint8).reshape(tensor_shape)
234
235    # run the inference
236    armnn_outputs = run_inference(test_data_folder, model_file_name, inputs, [armnn_delegate])
237
238    # check results
239    compare_outputs(armnn_outputs, [expected_output])