blob: 88be5a8e7fbfaf1f468baf7e806f1ee9b5b918d1 [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',
193 'AddBatchNormalizationLayer',
194 'AddBatchToSpaceNdLayer',
Teresa Charlin87dc8122021-11-22 15:34:26 +0000195 'AddCastLayer',
Teresa Charlinf7b50112021-11-18 15:24:50 +0000196 'AddChannelShuffleLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100197 'AddComparisonLayer',
198 'AddConcatLayer',
199 'AddConstantLayer',
200 'AddConvolution2dLayer',
Teresa Charlin18147332021-11-17 14:34:30 +0000201 'AddConvolution3dLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100202 'AddDepthToSpaceLayer',
203 'AddDepthwiseConvolution2dLayer',
204 'AddDequantizeLayer',
205 'AddDetectionPostProcessLayer',
206 'AddDivisionLayer',
207 'AddElementwiseUnaryLayer',
208 'AddFloorLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100209 'AddFillLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100210 'AddFullyConnectedLayer',
211 'AddGatherLayer',
Teresa Charlin26ee5422022-05-03 21:39:57 +0100212 'AddGatherNdLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100213 'AddInputLayer',
214 'AddInstanceNormalizationLayer',
Cathal Corbettf0836e02021-11-18 18:17:38 +0000215 'AddLogicalBinaryLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100216 'AddLogSoftmaxLayer',
217 'AddL2NormalizationLayer',
218 'AddLstmLayer',
219 'AddMaximumLayer',
220 'AddMeanLayer',
221 'AddMergeLayer',
222 'AddMinimumLayer',
223 'AddMultiplicationLayer',
224 'AddNormalizationLayer',
225 'AddOutputLayer',
226 'AddPadLayer',
227 'AddPermuteLayer',
228 'AddPooling2dLayer',
Ryan OShea89655002022-03-09 02:07:24 +0000229 'AddPooling3dLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100230 'AddPreluLayer',
231 'AddQuantizeLayer',
232 'AddQuantizedLstmLayer',
Jan Eilers841aca12020-08-12 14:59:06 +0100233 'AddRankLayer',
Ryan OShea09a05222021-11-18 16:52:41 +0000234 'AddReduceLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100235 'AddReshapeLayer',
236 'AddResizeLayer',
Ryan OSheaaeee9ad2021-11-18 17:43:55 +0000237 'AddShapeLayer',
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100238 'AddSliceLayer',
239 'AddSoftmaxLayer',
240 'AddSpaceToBatchNdLayer',
241 'AddSpaceToDepthLayer',
242 'AddSplitterLayer',
243 'AddStackLayer',
244 'AddStandInLayer',
245 'AddStridedSliceLayer',
246 'AddSubtractionLayer',
247 'AddSwitchLayer',
Cathal Corbett2b4182f2021-11-18 10:28:47 +0000248 'AddTransposeConvolution2dLayer',
249 'AddTransposeLayer'
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100250])
251def test_network_method_exists(method):
252 assert getattr(ann.INetwork, method, None)
253
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100254def test_Convolution2d_layer_optional_none():
255 net = ann.INetwork()
Teresa Charlind9360332022-08-30 14:27:10 +0100256 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor())
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100257
258 assert layer
259
260
261def test_Convolution2d_layer_all_args():
262 net = ann.INetwork()
263 layer = net.AddConvolution2dLayer(convolution2dDescriptor=ann.Convolution2dDescriptor(),
Cathal Corbett9f184c42021-11-10 12:14:39 +0000264 name='NAME1')
Richard Burtondc0c6ed2020-04-08 16:39:05 +0100265
266 assert layer
267 assert 'NAME1' == layer.GetName()
Cathal Corbett9f184c42021-11-10 12:14:39 +0000268
269
270def test_add_constant_layer_to_fully_connected():
271
272 inputWidth = 1
273 inputHeight = 1
274 inputChannels = 5
275 inputNum = 2
276
277 outputChannels = 3
278 outputNum = 2
279
280 inputShape = ( inputNum, inputChannels, inputHeight, inputWidth )
281 outputShape = ( outputNum, outputChannels )
282 weightsShape = ( inputChannels, outputChannels )
283 biasShape = ( outputChannels, )
284
285 input = np.array([
286 [1.0, 2.0, 3.0, 4.0, 5.0],
287 [5.0, 4.0, 3.0, 2.0, 1.0]
288 ], dtype=np.float32)
289
290 weights = np.array([
291 [.5, 2., .5],
292 [.5, 2., 1.],
293 [.5, 2., 2.],
294 [.5, 2., 3.],
295 [.5, 2., 4.]
296 ], dtype=np.float32)
297
298 biasValues = np.array([10, 20, 30], dtype=np.float32)
299
300 expectedOutput = np.array([
301 [0.5 + 1.0 + 1.5 + 2.0 + 2.5 + biasValues[0],
302 2.0 + 4.0 + 6.0 + 8.0 + 10. + biasValues[1],
303 0.5 + 2.0 + 6.0 + 12. + 20. + biasValues[2]],
304 [2.5 + 2.0 + 1.5 + 1.0 + 0.5 + biasValues[0],
305 10.0 + 8.0 + 6.0 + 4.0 + 2. + biasValues[1],
306 2.5 + 4.0 + 6.0 + 6. + 4. + biasValues[2]]
307 ], dtype=np.float32)
308
309 network = ann.INetwork()
310
311 input_info = ann.TensorInfo(ann.TensorShape(inputShape), ann.DataType_Float32, 0, 0, True)
312 input_tensor = ann.ConstTensor(input_info, input)
313 input_layer = network.AddInputLayer(0, "input")
314
315 w_info = ann.TensorInfo(ann.TensorShape(weightsShape), ann.DataType_Float32, 0, 0, True)
316 w_tensor = ann.ConstTensor(w_info, weights)
317 w_layer = network.AddConstantLayer(w_tensor, "weights")
318
319 b_info = ann.TensorInfo(ann.TensorShape(biasShape), ann.DataType_Float32, 0, 0, True)
320 b_tensor = ann.ConstTensor(b_info, biasValues)
321 b_layer = network.AddConstantLayer(b_tensor, "bias")
322
323 fc_descriptor = ann.FullyConnectedDescriptor()
324 fc_descriptor.m_BiasEnabled = True
325 fc_descriptor.m_ConstantWeights = True
326 fully_connected = network.AddFullyConnectedLayer(fc_descriptor, "fc")
327
328 output_info = ann.TensorInfo(ann.TensorShape(outputShape), ann.DataType_Float32)
329 output_tensor = ann.Tensor(output_info, np.zeros([1, 1], dtype=np.float32))
330 output = network.AddOutputLayer(0, "output")
331
332 input_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(0))
333 w_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(1))
334 b_layer.GetOutputSlot(0).Connect(fully_connected.GetInputSlot(2))
335 fully_connected.GetOutputSlot(0).Connect(output.GetInputSlot(0))
336
337 input_layer.GetOutputSlot(0).SetTensorInfo(input_info)
338 w_layer.GetOutputSlot(0).SetTensorInfo(w_info)
339 b_layer.GetOutputSlot(0).SetTensorInfo(b_info)
340 fully_connected.GetOutputSlot(0).SetTensorInfo(output_info)
341
342 preferred_backends = [ann.BackendId('CpuRef')]
343 options = ann.CreationOptions()
344 runtime = ann.IRuntime(options)
345 opt_network, messages = ann.Optimize(network, preferred_backends, runtime.GetDeviceSpec(), ann.OptimizerOptions())
346 net_id, messages = runtime.LoadNetwork(opt_network)
347
348 input_tensors = [(0, input_tensor)]
349 output_tensors = [(0, output_tensor)]
350 runtime.EnqueueWorkload(net_id, input_tensors, output_tensors)
351
352 output_vectors = ann.workload_tensors_to_ndarray(output_tensors)
353
354 assert (output_vectors==expectedOutput).all()