blob: 1792041e11f8739c2c5c78d122eba220059f9879 [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',
241 'AddTransposeConvolution2dLayer'
242])
243def test_network_method_exists(method):
244 assert getattr(ann.INetwork, method, None)
245
246
247def test_fullyconnected_layer_optional_none():
248 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000249 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
250 ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100251
252 assert layer
253
254
255def test_fullyconnected_layer_optional_provided():
256 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000257 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
258 ann.ConstTensor(),
259 ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100260
261 assert layer
262
263
264def test_fullyconnected_layer_all_args():
265 net = ann.INetwork()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000266 layer = net.AddFullyConnectedLayer(ann.FullyConnectedDescriptor(),
267 ann.ConstTensor(),
268 ann.ConstTensor(),
269 'NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100270
271 assert layer
272 assert 'NAME1' == layer.GetName()
273
274
275def test_DepthwiseConvolution2d_layer_optional_none():
276 net = ann.INetwork()
277 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000278 weights=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100279
280 assert layer
281
282
283def test_DepthwiseConvolution2d_layer_optional_provided():
284 net = ann.INetwork()
285 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000286 weights=ann.ConstTensor(),
287 biases=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100288
289 assert layer
290
291
292def test_DepthwiseConvolution2d_layer_all_args():
293 net = ann.INetwork()
294 layer = net.AddDepthwiseConvolution2dLayer(convolution2dDescriptor=ann.DepthwiseConvolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000295 weights=ann.ConstTensor(),
296 biases=ann.ConstTensor(),
297 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100298
299 assert layer
300 assert 'NAME1' == layer.GetName()
301
302
303def test_Convolution2d_layer_optional_none():
304 net = ann.INetwork()
305 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000306 weights=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100307
308 assert layer
309
310
311def test_Convolution2d_layer_optional_provided():
312 net = ann.INetwork()
313 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000314 weights=ann.ConstTensor(),
315 biases=ann.ConstTensor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100316
317 assert layer
318
319
320def test_Convolution2d_layer_all_args():
321 net = ann.INetwork()
322 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000323 weights=ann.ConstTensor(),
324 biases=ann.ConstTensor(),
325 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100326
327 assert layer
328 assert 'NAME1' == layer.GetName()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000329
330
331def test_add_constant_layer_to_fully_connected():
332
333 inputWidth = 1
334 inputHeight = 1
335 inputChannels = 5
336 inputNum = 2
337
338 outputChannels = 3
339 outputNum = 2
340
341 inputShape = ( inputNum, inputChannels, inputHeight, inputWidth )
342 outputShape = ( outputNum, outputChannels )
343 weightsShape = ( inputChannels, outputChannels )
344 biasShape = ( outputChannels, )
345
346 input = np.array([
347 [1.0, 2.0, 3.0, 4.0, 5.0],
348 [5.0, 4.0, 3.0, 2.0, 1.0]
349 ], dtype=np.float32)
350
351 weights = np.array([
352 [.5, 2., .5],
353 [.5, 2., 1.],
354 [.5, 2., 2.],
355 [.5, 2., 3.],
356 [.5, 2., 4.]
357 ], dtype=np.float32)
358
359 biasValues = np.array([10, 20, 30], dtype=np.float32)
360
361 expectedOutput = np.array([
362 [0.5 + 1.0 + 1.5 + 2.0 + 2.5 + biasValues[0],
363 2.0 + 4.0 + 6.0 + 8.0 + 10. + biasValues[1],
364 0.5 + 2.0 + 6.0 + 12. + 20. + biasValues[2]],
365 [2.5 + 2.0 + 1.5 + 1.0 + 0.5 + biasValues[0],
366 10.0 + 8.0 + 6.0 + 4.0 + 2. + biasValues[1],
367 2.5 + 4.0 + 6.0 + 6. + 4. + biasValues[2]]
368 ], dtype=np.float32)
369
370 network = ann.INetwork()
371
372 input_info = ann.TensorInfo(ann.TensorShape(inputShape), ann.DataType_Float32, 0, 0, True)
373 input_tensor = ann.ConstTensor(input_info, input)
374 input_layer = network.AddInputLayer(0, "input")
375
376 w_info = ann.TensorInfo(ann.TensorShape(weightsShape), ann.DataType_Float32, 0, 0, True)
377 w_tensor = ann.ConstTensor(w_info, weights)
378 w_layer = network.AddConstantLayer(w_tensor, "weights")
379
380 b_info = ann.TensorInfo(ann.TensorShape(biasShape), ann.DataType_Float32, 0, 0, True)
381 b_tensor = ann.ConstTensor(b_info, biasValues)
382 b_layer = network.AddConstantLayer(b_tensor, "bias")
383
384 fc_descriptor = ann.FullyConnectedDescriptor()
385 fc_descriptor.m_BiasEnabled = True
386 fc_descriptor.m_ConstantWeights = True
387 fully_connected = network.AddFullyConnectedLayer(fc_descriptor, "fc")
388
389 output_info = ann.TensorInfo(ann.TensorShape(outputShape), ann.DataType_Float32)
390 output_tensor = ann.Tensor(output_info, np.zeros([1, 1], dtype=np.float32))
391 output = network.AddOutputLayer(0, "output")
392
393 input_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(0))
394 w_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(1))
395 b_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(2))
396 fully_connected.GetOutputSlot(0).Connect(output.GetInputSlot(0))
397
398 input_layer.GetOutputSlot(0).SetTensorInfo(input_info)
399 w_layer.GetOutputSlot(0).SetTensorInfo(w_info)
400 b_layer.GetOutputSlot(0).SetTensorInfo(b_info)
401 fully_connected.GetOutputSlot(0).SetTensorInfo(output_info)
402
403 preferred_backends = [ann.BackendId('CpuRef')]
404 options = ann.CreationOptions()
405 runtime = ann.IRuntime(options)
406 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
407 net_id, messages = runtime.LoadNetwork(opt_network)
408
409 input_tensors = [(0, input_tensor)]
410 output_tensors = [(0, output_tensor)]
411 runtime.EnqueueWorkload(net_id, input_tensors, output_tensors)
412
413 output_vectors = ann.workload_tensors_to_ndarray(output_tensors)
414
415 assert (output_vectors==expectedOutput).all()