blob: ff1c66edc4d79943d9d9d860cfe79347a009350c [file] [log] [blame]
Richard Burtondc0c6ed2020-04-08 16:39:05 +01001# Copyright © 2020 Arm Ltd. All rights reserved.
2# 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',
193 'AddBatchNormalizationLayer',
194 'AddBatchToSpaceNdLayer',
195 'AddComparisonLayer',
196 'AddConcatLayer',
197 'AddConstantLayer',
198 'AddConvolution2dLayer',
199 'AddDepthToSpaceLayer',
200 'AddDepthwiseConvolution2dLayer',
201 'AddDequantizeLayer',
202 'AddDetectionPostProcessLayer',
203 'AddDivisionLayer',
204 'AddElementwiseUnaryLayer',
205 'AddFloorLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100206 'AddFillLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100207 'AddFullyConnectedLayer',
208 'AddGatherLayer',
209 'AddInputLayer',
210 'AddInstanceNormalizationLayer',
Cathal Corbettf0836e02021-11-18 18:17:38 +0000211 'AddLogicalBinaryLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100212 'AddLogSoftmaxLayer',
213 'AddL2NormalizationLayer',
214 'AddLstmLayer',
215 'AddMaximumLayer',
216 'AddMeanLayer',
217 'AddMergeLayer',
218 'AddMinimumLayer',
219 'AddMultiplicationLayer',
220 'AddNormalizationLayer',
221 'AddOutputLayer',
222 'AddPadLayer',
223 'AddPermuteLayer',
224 'AddPooling2dLayer',
225 'AddPreluLayer',
226 'AddQuantizeLayer',
227 'AddQuantizedLstmLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100228 'AddRankLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100229 'AddReshapeLayer',
230 'AddResizeLayer',
231 'AddSliceLayer',
232 'AddSoftmaxLayer',
233 'AddSpaceToBatchNdLayer',
234 'AddSpaceToDepthLayer',
235 'AddSplitterLayer',
236 'AddStackLayer',
237 'AddStandInLayer',
238 'AddStridedSliceLayer',
239 'AddSubtractionLayer',
240 'AddSwitchLayer',
Cathal Corbett2b4182f2021-11-18 10:28:47 +0000241 'AddTransposeConvolution2dLayer',
242 'AddTransposeLayer'
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100243])
244def test_network_method_exists(method):
245 assert getattr(ann.INetwork, method, None)
246
247
248def test_fullyconnected_layer_optional_none():
249 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000250 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
251 ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100252
253 assert layer
254
255
256def test_fullyconnected_layer_optional_provided():
257 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000258 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
259 ann.ConstTensor(),
260 ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100261
262 assert layer
263
264
265def test_fullyconnected_layer_all_args():
266 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000267 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
268 ann.ConstTensor(),
269 ann.ConstTensor(),
270 'NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100271
272 assert layer
273 assert 'NAME1' == layer.GetName()
274
275
276def test_DepthwiseConvolution2d_layer_optional_none():
277 net = ann.INetwork()
278 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000279 weights=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100280
281 assert layer
282
283
284def test_DepthwiseConvolution2d_layer_optional_provided():
285 net = ann.INetwork()
286 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000287 weights=ann.ConstTensor(),
288 biases=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100289
290 assert layer
291
292
293def test_DepthwiseConvolution2d_layer_all_args():
294 net = ann.INetwork()
295 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000296 weights=ann.ConstTensor(),
297 biases=ann.ConstTensor(),
298 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100299
300 assert layer
301 assert 'NAME1' == layer.GetName()
302
303
304def test_Convolution2d_layer_optional_none():
305 net = ann.INetwork()
306 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000307 weights=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100308
309 assert layer
310
311
312def test_Convolution2d_layer_optional_provided():
313 net = ann.INetwork()
314 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000315 weights=ann.ConstTensor(),
316 biases=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100317
318 assert layer
319
320
321def test_Convolution2d_layer_all_args():
322 net = ann.INetwork()
323 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000324 weights=ann.ConstTensor(),
325 biases=ann.ConstTensor(),
326 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100327
328 assert layer
329 assert 'NAME1' == layer.GetName()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000330
331
332def test_add_constant_layer_to_fully_connected():
333
334 inputWidth = 1
335 inputHeight = 1
336 inputChannels = 5
337 inputNum = 2
338
339 outputChannels = 3
340 outputNum = 2
341
342 inputShape = ( inputNum, inputChannels, inputHeight, inputWidth )
343 outputShape = ( outputNum, outputChannels )
344 weightsShape = ( inputChannels, outputChannels )
345 biasShape = ( outputChannels, )
346
347 input = np.array([
348 [1.0, 2.0, 3.0, 4.0, 5.0],
349 [5.0, 4.0, 3.0, 2.0, 1.0]
350 ], dtype=np.float32)
351
352 weights = np.array([
353 [.5, 2., .5],
354 [.5, 2., 1.],
355 [.5, 2., 2.],
356 [.5, 2., 3.],
357 [.5, 2., 4.]
358 ], dtype=np.float32)
359
360 biasValues = np.array([10, 20, 30], dtype=np.float32)
361
362 expectedOutput = np.array([
363 [0.5 + 1.0 + 1.5 + 2.0 + 2.5 + biasValues[0],
364 2.0 + 4.0 + 6.0 + 8.0 + 10. + biasValues[1],
365 0.5 + 2.0 + 6.0 + 12. + 20. + biasValues[2]],
366 [2.5 + 2.0 + 1.5 + 1.0 + 0.5 + biasValues[0],
367 10.0 + 8.0 + 6.0 + 4.0 + 2. + biasValues[1],
368 2.5 + 4.0 + 6.0 + 6. + 4. + biasValues[2]]
369 ], dtype=np.float32)
370
371 network = ann.INetwork()
372
373 input_info = ann.TensorInfo(ann.TensorShape(inputShape), ann.DataType_Float32, 0, 0, True)
374 input_tensor = ann.ConstTensor(input_info, input)
375 input_layer = network.AddInputLayer(0, "input")
376
377 w_info = ann.TensorInfo(ann.TensorShape(weightsShape), ann.DataType_Float32, 0, 0, True)
378 w_tensor = ann.ConstTensor(w_info, weights)
379 w_layer = network.AddConstantLayer(w_tensor, "weights")
380
381 b_info = ann.TensorInfo(ann.TensorShape(biasShape), ann.DataType_Float32, 0, 0, True)
382 b_tensor = ann.ConstTensor(b_info, biasValues)
383 b_layer = network.AddConstantLayer(b_tensor, "bias")
384
385 fc_descriptor = ann.FullyConnectedDescriptor()
386 fc_descriptor.m_BiasEnabled = True
387 fc_descriptor.m_ConstantWeights = True
388 fully_connected = network.AddFullyConnectedLayer(fc_descriptor, "fc")
389
390 output_info = ann.TensorInfo(ann.TensorShape(outputShape), ann.DataType_Float32)
391 output_tensor = ann.Tensor(output_info, np.zeros([1, 1], dtype=np.float32))
392 output = network.AddOutputLayer(0, "output")
393
394 input_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(0))
395 w_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(1))
396 b_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(2))
397 fully_connected.GetOutputSlot(0).Connect(output.GetInputSlot(0))
398
399 input_layer.GetOutputSlot(0).SetTensorInfo(input_info)
400 w_layer.GetOutputSlot(0).SetTensorInfo(w_info)
401 b_layer.GetOutputSlot(0).SetTensorInfo(b_info)
402 fully_connected.GetOutputSlot(0).SetTensorInfo(output_info)
403
404 preferred_backends = [ann.BackendId('CpuRef')]
405 options = ann.CreationOptions()
406 runtime = ann.IRuntime(options)
407 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
408 net_id, messages = runtime.LoadNetwork(opt_network)
409
410 input_tensors = [(0, input_tensor)]
411 output_tensors = [(0, output_tensor)]
412 runtime.EnqueueWorkload(net_id, input_tensors, output_tensors)
413
414 output_vectors = ann.workload_tensors_to_ndarray(output_tensors)
415
416 assert (output_vectors==expectedOutput).all()