blob: 91602b8fa8595e0b65cae2e182c853b2567d3e64 [file] [log] [blame]
Teresa Charlin18147332021-11-17 14:34:30 +00001# Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
Richard Burtondc0c6ed2020-04-08 16:39:05 +01002# SPDX-License-Identifier: MIT
3import os
4import stat
Cathal Corbett9f184c42021-11-10 12:14:39 +00005import numpy as np
Richard Burtondc0c6ed2020-04-08 16:39:05 +01006
7import pytest
8import pyarmnn as ann
9
alexander73010782021-10-18 19:17:24 +010010
Jan Eilers841aca12020-08-12 14:59:06 +010011def test_optimizer_options_default_values():
12 opt = ann.OptimizerOptions()
13 assert opt.m_ReduceFp32ToFp16 == False
14 assert opt.m_Debug == False
15 assert opt.m_ReduceFp32ToBf16 == False
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010016 assert opt.m_ImportEnabled == False
alexander73010782021-10-18 19:17:24 +010017 assert opt.m_shapeInferenceMethod == ann.ShapeInferenceMethod_ValidateOnly
18
Jan Eilers841aca12020-08-12 14:59:06 +010019
20def test_optimizer_options_set_values1():
21 opt = ann.OptimizerOptions(True, True)
22 assert opt.m_ReduceFp32ToFp16 == True
23 assert opt.m_Debug == True
24 assert opt.m_ReduceFp32ToBf16 == False
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010025 assert opt.m_ImportEnabled == False
alexander73010782021-10-18 19:17:24 +010026 assert opt.m_shapeInferenceMethod == ann.ShapeInferenceMethod_ValidateOnly
27
Jan Eilers841aca12020-08-12 14:59:06 +010028
29def test_optimizer_options_set_values2():
30 opt = ann.OptimizerOptions(False, False, True)
31 assert opt.m_ReduceFp32ToFp16 == False
32 assert opt.m_Debug == False
33 assert opt.m_ReduceFp32ToBf16 == True
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010034 assert opt.m_ImportEnabled == False
alexander73010782021-10-18 19:17:24 +010035 assert opt.m_shapeInferenceMethod == ann.ShapeInferenceMethod_ValidateOnly
36
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010037
38def test_optimizer_options_set_values3():
alexander73010782021-10-18 19:17:24 +010039 opt = ann.OptimizerOptions(False, False, True, ann.ShapeInferenceMethod_InferAndValidate, True)
Narumol Prangnawaratea063df2020-08-21 10:03:49 +010040 assert opt.m_ReduceFp32ToFp16 == False
41 assert opt.m_Debug == False
42 assert opt.m_ReduceFp32ToBf16 == True
43 assert opt.m_ImportEnabled == True
alexander73010782021-10-18 19:17:24 +010044 assert opt.m_shapeInferenceMethod == ann.ShapeInferenceMethod_InferAndValidate
45
Richard Burtondc0c6ed2020-04-08 16:39:05 +010046
47@pytest.fixture(scope="function")
48def get_runtime(shared_data_folder, network_file):
49 parser= ann.ITfLiteParser()
50 preferred_backends = [ann.BackendId('CpuAcc'), ann.BackendId('CpuRef')]
51 network = parser.CreateNetworkFromBinaryFile(os.path.join(shared_data_folder, network_file))
52 options = ann.CreationOptions()
53 runtime = ann.IRuntime(options)
54
55 yield preferred_backends, network, runtime
56
57
58@pytest.mark.parametrize("network_file",
59 [
60 'mock_model.tflite',
61 ],
62 ids=['mock_model'])
63def test_optimize_executes_successfully(network_file, get_runtime):
64 preferred_backends = [ann.BackendId('CpuRef')]
65 network = get_runtime[1]
66 runtime = get_runtime[2]
67
68 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
69
70 assert len(messages) == 0, 'With only CpuRef, there should be no warnings irrelevant of architecture.'
71 assert opt_network
72
73
74@pytest.mark.parametrize("network_file",
75 [
76 'mock_model.tflite',
77 ],
78 ids=['mock_model'])
79def test_optimize_owned_by_python(network_file, get_runtime):
80 preferred_backends = get_runtime[0]
81 network = get_runtime[1]
82 runtime = get_runtime[2]
83
84 opt_network, _ = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
85 assert opt_network.thisown
86
87
88@pytest.mark.aarch64
89@pytest.mark.parametrize("network_file",
90 [
91 'mock_model.tflite'
92 ],
93 ids=['mock_model'])
94def test_optimize_executes_successfully_for_neon_backend_only(network_file, get_runtime):
95 preferred_backends = [ann.BackendId('CpuAcc')]
96 network = get_runtime[1]
97 runtime = get_runtime[2]
98
99 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
100 assert 0 == len(messages)
101 assert opt_network
102
103
104@pytest.mark.parametrize("network_file",
105 [
106 'mock_model.tflite'
107 ],
108 ids=['mock_model'])
109def test_optimize_fails_for_invalid_backends(network_file, get_runtime):
110 invalid_backends = [ann.BackendId('Unknown')]
111 network = get_runtime[1]
112 runtime = get_runtime[2]
113
114 with pytest.raises(RuntimeError) as err:
115 ann.Optimize(network, invalid_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
116
117 expected_error_message = "None of the preferred backends [Unknown ] are supported."
118 assert expected_error_message in str(err.value)
119
120
121@pytest.mark.parametrize("network_file",
122 [
123 'mock_model.tflite'
124 ],
125 ids=['mock_model'])
126def test_optimize_fails_for_no_backends_specified(network_file, get_runtime):
127 empty_backends = []
128 network = get_runtime[1]
129 runtime = get_runtime[2]
130
131 with pytest.raises(RuntimeError) as err:
132 ann.Optimize(network, empty_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
133
134 expected_error_message = "Invoked Optimize with no backends specified"
135 assert expected_error_message in str(err.value)
136
137
138@pytest.mark.parametrize("network_file",
139 [
140 'mock_model.tflite'
141 ],
142 ids=['mock_model'])
143def test_serialize_to_dot(network_file, get_runtime, tmpdir):
144 preferred_backends = get_runtime[0]
145 network = get_runtime[1]
146 runtime = get_runtime[2]
147 opt_network, _ = ann.Optimize(network, preferred_backends,
148 runtime.GetDeviceSpec(), ann.OptimizerOptions())
149 dot_file_path = os.path.join(tmpdir, 'mock_model.dot')
150 """Check that serialized file does not exist at the start, gets created after SerializeToDot and is not empty"""
151 assert not os.path.exists(dot_file_path)
152 opt_network.SerializeToDot(dot_file_path)
153
154 assert os.path.exists(dot_file_path)
155
156 with open(dot_file_path) as res_file:
157 expected_data = res_file.read()
158 assert len(expected_data) > 1
159 assert '[label=< [1,28,28,1] >]' in expected_data
160
161
162@pytest.mark.x86_64
163@pytest.mark.parametrize("network_file",
164 [
165 'mock_model.tflite'
166 ],
167 ids=['mock_model'])
168def test_serialize_to_dot_mode_readonly(network_file, get_runtime, tmpdir):
169 preferred_backends = get_runtime[0]
170 network = get_runtime[1]
171 runtime = get_runtime[2]
172 opt_network, _ = ann.Optimize(network, preferred_backends,
173 runtime.GetDeviceSpec(), ann.OptimizerOptions())
174 """Create file, write to it and change mode to read-only"""
175 dot_file_path = os.path.join(tmpdir, 'mock_model.dot')
176 f = open(dot_file_path, "w+")
177 f.write("test")
178 f.close()
179 os.chmod(dot_file_path, stat.S_IREAD)
180 assert os.path.exists(dot_file_path)
181
182 with pytest.raises(RuntimeError) as err:
183 opt_network.SerializeToDot(dot_file_path)
184
185 expected_error_message = "Failed to open dot file"
186 assert expected_error_message in str(err.value)
187
188
189@pytest.mark.parametrize("method", [
190 'AddActivationLayer',
191 'AddAdditionLayer',
192 'AddArgMinMaxLayer',
Ryan OShea083802d2023-07-28 17:35:18 +0100193 'AddBatchMatMulLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100194 'AddBatchNormalizationLayer',
195 'AddBatchToSpaceNdLayer',
Teresa Charlin87dc8122021-11-22 15:34:26 +0000196 'AddCastLayer',
Teresa Charlinf7b50112021-11-18 15:24:50 +0000197 'AddChannelShuffleLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100198 'AddComparisonLayer',
199 'AddConcatLayer',
200 'AddConstantLayer',
201 'AddConvolution2dLayer',
Teresa Charlin18147332021-11-17 14:34:30 +0000202 'AddConvolution3dLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100203 'AddDepthToSpaceLayer',
204 'AddDepthwiseConvolution2dLayer',
205 'AddDequantizeLayer',
206 'AddDetectionPostProcessLayer',
207 'AddDivisionLayer',
Ryan OShea083802d2023-07-28 17:35:18 +0100208 'AddElementwiseBinaryLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100209 'AddElementwiseUnaryLayer',
210 'AddFloorLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100211 'AddFillLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100212 'AddFullyConnectedLayer',
213 'AddGatherLayer',
Teresa Charlin26ee5422022-05-03 21:39:57 +0100214 'AddGatherNdLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100215 'AddInputLayer',
216 'AddInstanceNormalizationLayer',
Cathal Corbettf0836e02021-11-18 18:17:38 +0000217 'AddLogicalBinaryLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100218 'AddLogSoftmaxLayer',
219 'AddL2NormalizationLayer',
220 'AddLstmLayer',
221 'AddMaximumLayer',
222 'AddMeanLayer',
223 'AddMergeLayer',
224 'AddMinimumLayer',
225 'AddMultiplicationLayer',
226 'AddNormalizationLayer',
227 'AddOutputLayer',
228 'AddPadLayer',
229 'AddPermuteLayer',
230 'AddPooling2dLayer',
Ryan OShea89655002022-03-09 02:07:24 +0000231 'AddPooling3dLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100232 'AddPreluLayer',
233 'AddQuantizeLayer',
234 'AddQuantizedLstmLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100235 'AddRankLayer',
Ryan OShea09a05222021-11-18 16:52:41 +0000236 'AddReduceLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100237 'AddReshapeLayer',
238 'AddResizeLayer',
Ryan OShea083802d2023-07-28 17:35:18 +0100239 'AddReverseV2Layer',
Ryan OSheaaeee9ad2021-11-18 17:43:55 +0000240 'AddShapeLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100241 'AddSliceLayer',
242 'AddSoftmaxLayer',
243 'AddSpaceToBatchNdLayer',
244 'AddSpaceToDepthLayer',
245 'AddSplitterLayer',
246 'AddStackLayer',
247 'AddStandInLayer',
248 'AddStridedSliceLayer',
249 'AddSubtractionLayer',
250 'AddSwitchLayer',
Ryan OShea083802d2023-07-28 17:35:18 +0100251 'AddTileLayer',
Cathal Corbett2b4182f2021-11-18 10:28:47 +0000252 'AddTransposeConvolution2dLayer',
253 'AddTransposeLayer'
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100254])
255def test_network_method_exists(method):
256 assert getattr(ann.INetwork, method, None)
257
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100258def test_Convolution2d_layer_optional_none():
259 net = ann.INetwork()
Teresa Charlind9360332022-08-30 14:27:10 +0100260 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100261
262 assert layer
263
264
265def test_Convolution2d_layer_all_args():
266 net = ann.INetwork()
267 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000268 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100269
270 assert layer
271 assert 'NAME1' == layer.GetName()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000272
273
274def test_add_constant_layer_to_fully_connected():
275
276 inputWidth = 1
277 inputHeight = 1
278 inputChannels = 5
279 inputNum = 2
280
281 outputChannels = 3
282 outputNum = 2
283
284 inputShape = ( inputNum, inputChannels, inputHeight, inputWidth )
285 outputShape = ( outputNum, outputChannels )
286 weightsShape = ( inputChannels, outputChannels )
287 biasShape = ( outputChannels, )
288
289 input = np.array([
290 [1.0, 2.0, 3.0, 4.0, 5.0],
291 [5.0, 4.0, 3.0, 2.0, 1.0]
292 ], dtype=np.float32)
293
294 weights = np.array([
295 [.5, 2., .5],
296 [.5, 2., 1.],
297 [.5, 2., 2.],
298 [.5, 2., 3.],
299 [.5, 2., 4.]
300 ], dtype=np.float32)
301
302 biasValues = np.array([10, 20, 30], dtype=np.float32)
303
304 expectedOutput = np.array([
305 [0.5 + 1.0 + 1.5 + 2.0 + 2.5 + biasValues[0],
306 2.0 + 4.0 + 6.0 + 8.0 + 10. + biasValues[1],
307 0.5 + 2.0 + 6.0 + 12. + 20. + biasValues[2]],
308 [2.5 + 2.0 + 1.5 + 1.0 + 0.5 + biasValues[0],
309 10.0 + 8.0 + 6.0 + 4.0 + 2. + biasValues[1],
310 2.5 + 4.0 + 6.0 + 6. + 4. + biasValues[2]]
311 ], dtype=np.float32)
312
313 network = ann.INetwork()
314
315 input_info = ann.TensorInfo(ann.TensorShape(inputShape), ann.DataType_Float32, 0, 0, True)
316 input_tensor = ann.ConstTensor(input_info, input)
317 input_layer = network.AddInputLayer(0, "input")
318
319 w_info = ann.TensorInfo(ann.TensorShape(weightsShape), ann.DataType_Float32, 0, 0, True)
320 w_tensor = ann.ConstTensor(w_info, weights)
321 w_layer = network.AddConstantLayer(w_tensor, "weights")
322
323 b_info = ann.TensorInfo(ann.TensorShape(biasShape), ann.DataType_Float32, 0, 0, True)
324 b_tensor = ann.ConstTensor(b_info, biasValues)
325 b_layer = network.AddConstantLayer(b_tensor, "bias")
326
327 fc_descriptor = ann.FullyConnectedDescriptor()
328 fc_descriptor.m_BiasEnabled = True
329 fc_descriptor.m_ConstantWeights = True
330 fully_connected = network.AddFullyConnectedLayer(fc_descriptor, "fc")
331
332 output_info = ann.TensorInfo(ann.TensorShape(outputShape), ann.DataType_Float32)
333 output_tensor = ann.Tensor(output_info, np.zeros([1, 1], dtype=np.float32))
334 output = network.AddOutputLayer(0, "output")
335
336 input_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(0))
337 w_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(1))
338 b_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(2))
339 fully_connected.GetOutputSlot(0).Connect(output.GetInputSlot(0))
340
341 input_layer.GetOutputSlot(0).SetTensorInfo(input_info)
342 w_layer.GetOutputSlot(0).SetTensorInfo(w_info)
343 b_layer.GetOutputSlot(0).SetTensorInfo(b_info)
344 fully_connected.GetOutputSlot(0).SetTensorInfo(output_info)
345
346 preferred_backends = [ann.BackendId('CpuRef')]
347 options = ann.CreationOptions()
348 runtime = ann.IRuntime(options)
349 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
350 net_id, messages = runtime.LoadNetwork(opt_network)
351
352 input_tensors = [(0, input_tensor)]
353 output_tensors = [(0, output_tensor)]
354 runtime.EnqueueWorkload(net_id, input_tensors, output_tensors)
355
356 output_vectors = ann.workload_tensors_to_ndarray(output_tensors)
357
358 assert (output_vectors==expectedOutput).all()