blob: c15e33fc1333e294426222134d8dc9fe5489beef [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
Sadik Armagana9c2ce12020-07-14 10:02:22 +01002// Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
telsoa01c577f2c2018-08-31 09:22:23 +01005
Francis Murtaghbee4bc92019-06-18 12:30:37 +01006#include "../NetworkExecutionUtils/NetworkExecutionUtils.hpp"
telsoa01c577f2c2018-08-31 09:22:23 +01007
James Conroy7b4886f2019-04-11 10:23:58 +01008// MAIN
telsoa01c577f2c2018-08-31 09:22:23 +01009int main(int argc, const char* argv[])
10{
11 // Configures logging for both the ARMNN library and this test program.
12#ifdef NDEBUG
13 armnn::LogSeverity level = armnn::LogSeverity::Info;
14#else
15 armnn::LogSeverity level = armnn::LogSeverity::Debug;
16#endif
17 armnn::ConfigureLogging(true, true, level);
telsoa01c577f2c2018-08-31 09:22:23 +010018
19 std::string testCasesFile;
20
21 std::string modelFormat;
22 std::string modelPath;
Ferran Balaguerc602f292019-02-08 17:09:55 +000023 std::string inputNames;
24 std::string inputTensorShapes;
25 std::string inputTensorDataFilePaths;
26 std::string outputNames;
27 std::string inputTypes;
Éanna Ó Catháinb3d481a2019-02-26 11:26:24 +000028 std::string outputTypes;
Matteo Martincigh00dda4a2019-08-14 11:42:30 +010029 std::string dynamicBackendsPath;
Sadik Armagan77086282019-09-02 11:46:28 +010030 std::string outputTensorFiles;
telsoa01c577f2c2018-08-31 09:22:23 +010031
Jim Flynn4951b8c2019-10-03 10:04:30 -070032 // external profiling parameters
33 std::string outgoingCaptureFile;
34 std::string incomingCaptureFile;
35 uint32_t counterCapturePeriod;
Isabella Gottardia0687ee2020-03-11 18:04:20 +000036 std::string fileFormat;
Jim Flynn4951b8c2019-10-03 10:04:30 -070037
alered01a7227ac2020-05-07 14:58:29 +010038 size_t iterations = 1;
39 int tuningLevel = 0;
40 std::string tuningPath;
41
James Conroy7b4886f2019-04-11 10:23:58 +010042 double thresholdTime = 0.0;
43
telsoa01c577f2c2018-08-31 09:22:23 +010044 size_t subgraphId = 0;
45
Matthew Jackson07882f12019-09-05 15:55:55 +010046 const std::string backendsMessage = "REQUIRED: Which device to run layers on by default. Possible choices: "
Aron Virginas-Tar5cc8e562018-10-23 15:14:46 +010047 + armnn::BackendRegistryInstance().GetBackendIdsAsString();
telsoa01c577f2c2018-08-31 09:22:23 +010048 po::options_description desc("Options");
49 try
50 {
51 desc.add_options()
52 ("help", "Display usage information")
Matthew Jackson07882f12019-09-05 15:55:55 +010053 ("compute,c", po::value<std::vector<std::string>>()->multitoken()->required(),
54 backendsMessage.c_str())
telsoa01c577f2c2018-08-31 09:22:23 +010055 ("test-cases,t", po::value(&testCasesFile), "Path to a CSV file containing test cases to run. "
56 "If set, further parameters -- with the exception of compute device and concurrency -- will be ignored, "
57 "as they are expected to be defined in the file for each test in particular.")
58 ("concurrent,n", po::bool_switch()->default_value(false),
59 "Whether or not the test cases should be executed in parallel")
Matteo Martincigh49124022019-01-11 13:25:59 +000060 ("model-format,f", po::value(&modelFormat)->required(),
Aron Virginas-Tar64e4ccb2019-02-12 11:27:53 +000061 "armnn-binary, caffe-binary, caffe-text, onnx-binary, onnx-text, tflite-binary, tensorflow-binary or "
62 "tensorflow-text.")
63 ("model-path,m", po::value(&modelPath)->required(), "Path to model file, e.g. .armnn, .caffemodel, "
64 ".prototxt, .tflite, .onnx")
Matteo Martincigh00dda4a2019-08-14 11:42:30 +010065 ("dynamic-backends-path,b", po::value(&dynamicBackendsPath),
66 "Path where to load any available dynamic backend from. "
67 "If left empty (the default), dynamic backends will not be used.")
Ferran Balaguerc602f292019-02-08 17:09:55 +000068 ("input-name,i", po::value(&inputNames),
69 "Identifier of the input tensors in the network separated by comma.")
telsoa01c577f2c2018-08-31 09:22:23 +010070 ("subgraph-number,x", po::value<size_t>(&subgraphId)->default_value(0), "Id of the subgraph to be executed."
71 "Defaults to 0")
Ferran Balaguerc602f292019-02-08 17:09:55 +000072 ("input-tensor-shape,s", po::value(&inputTensorShapes),
Francis Murtagh1555cbd2019-10-08 14:47:46 +010073 "The shape of the input tensors in the network as a flat array of integers separated by comma."
74 "Several shapes can be passed by separating them with a colon (:)."
telsoa01c577f2c2018-08-31 09:22:23 +010075 "This parameter is optional, depending on the network.")
Aron Virginas-Tarc82c8732019-10-24 17:07:43 +010076 ("input-tensor-data,d", po::value(&inputTensorDataFilePaths)->default_value(""),
Ferran Balaguerc602f292019-02-08 17:09:55 +000077 "Path to files containing the input data as a flat array separated by whitespace. "
Aron Virginas-Tarc82c8732019-10-24 17:07:43 +010078 "Several paths can be passed by separating them with a comma. If not specified, the network will be run "
79 "with dummy data (useful for profiling).")
Ferran Balaguerc602f292019-02-08 17:09:55 +000080 ("input-type,y",po::value(&inputTypes), "The type of the input tensors in the network separated by comma. "
81 "If unset, defaults to \"float\" for all defined inputs. "
Éanna Ó Catháinb3d481a2019-02-26 11:26:24 +000082 "Accepted values (float, int or qasymm8)")
Narumol Prangnawarat610256f2019-06-26 15:10:46 +010083 ("quantize-input,q",po::bool_switch()->default_value(false),
84 "If this option is enabled, all float inputs will be quantized to qasymm8. "
85 "If unset, default to not quantized. "
86 "Accepted values (true or false)")
Éanna Ó Catháinb3d481a2019-02-26 11:26:24 +000087 ("output-type,z",po::value(&outputTypes),
88 "The type of the output tensors in the network separated by comma. "
89 "If unset, defaults to \"float\" for all defined outputs. "
90 "Accepted values (float, int or qasymm8).")
Georgios Pinitas50311ba2020-02-18 13:25:23 +000091 ("dequantize-output,l",po::bool_switch()->default_value(false),
92 "If this option is enabled, all quantized outputs will be dequantized to float. "
93 "If unset, default to not get dequantized. "
94 "Accepted values (true or false)")
Ferran Balaguerc602f292019-02-08 17:09:55 +000095 ("output-name,o", po::value(&outputNames),
96 "Identifier of the output tensors in the network separated by comma.")
Sadik Armagan77086282019-09-02 11:46:28 +010097 ("write-outputs-to-file,w", po::value(&outputTensorFiles),
98 "Comma-separated list of output file paths keyed with the binding-id of the output slot. "
99 "If left empty (the default), the output tensors will not be written to a file.")
telsoa01c577f2c2018-08-31 09:22:23 +0100100 ("event-based-profiling,e", po::bool_switch()->default_value(false),
Ruomei Yan2fcce082019-04-02 16:47:34 +0100101 "Enables built in profiler. If unset, defaults to off.")
Andre Ghattas23ae2ea2019-08-07 12:18:38 +0100102 ("visualize-optimized-model,v", po::bool_switch()->default_value(false),
103 "Enables built optimized model visualizer. If unset, defaults to off.")
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000104 ("bf16-turbo-mode", po::bool_switch()->default_value(false), "If this option is enabled, FP32 layers, "
105 "weights and biases will be converted to BFloat16 where the backend supports it")
Ruomei Yan2fcce082019-04-02 16:47:34 +0100106 ("fp16-turbo-mode,h", po::bool_switch()->default_value(false), "If this option is enabled, FP32 layers, "
James Conroy7b4886f2019-04-11 10:23:58 +0100107 "weights and biases will be converted to FP16 where the backend supports it")
108 ("threshold-time,r", po::value<double>(&thresholdTime)->default_value(0.0),
109 "Threshold time is the maximum allowed time for inference measured in milliseconds. If the actual "
110 "inference time is greater than the threshold time, the test will fail. By default, no threshold "
Matthew Jackson54658b92019-08-27 15:35:59 +0100111 "time is used.")
112 ("print-intermediate-layers,p", po::bool_switch()->default_value(false),
Jim Flynn4951b8c2019-10-03 10:04:30 -0700113 "If this option is enabled, the output of every graph layer will be printed.")
114 ("enable-external-profiling,a", po::bool_switch()->default_value(false),
115 "If enabled external profiling will be switched on")
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100116 ("timeline-profiling", po::bool_switch()->default_value(false),
117 "If enabled timeline profiling will be switched on, requires external profiling")
Jim Flynn4951b8c2019-10-03 10:04:30 -0700118 ("outgoing-capture-file,j", po::value(&outgoingCaptureFile),
119 "If specified the outgoing external profiling packets will be captured in this binary file")
120 ("incoming-capture-file,k", po::value(&incomingCaptureFile),
121 "If specified the incoming external profiling packets will be captured in this binary file")
122 ("file-only-external-profiling,g", po::bool_switch()->default_value(false),
123 "If enabled then the 'file-only' test mode of external profiling will be enabled")
124 ("counter-capture-period,u", po::value<uint32_t>(&counterCapturePeriod)->default_value(150u),
Derek Lamberti132563c2019-12-02 16:06:40 +0000125 "If profiling is enabled in 'file-only' mode this is the capture period that will be used in the test")
Finn Williams50616012020-05-13 17:19:14 +0100126 ("file-format", po::value(&fileFormat)->default_value("binary"),
Isabella Gottardia0687ee2020-03-11 18:04:20 +0000127 "If profiling is enabled specifies the output file format")
alered01a7227ac2020-05-07 14:58:29 +0100128 ("iterations", po::value<size_t>(&iterations)->default_value(1),
129 "Number of iterations to run the network for, default is set to 1")
130 ("tuning-path", po::value(&tuningPath),
131 "Path to tuning file. Enables use of CL tuning")
132 ("tuning-level", po::value<int>(&tuningLevel)->default_value(0),
133 "Sets the tuning level which enables a tuning run which will update/create a tuning file. "
134 "Available options are: 1 (Rapid), 2 (Normal), 3 (Exhaustive). "
135 "Requires tuning-path to be set, default is set to 0 (No tuning run)")
Derek Lamberti132563c2019-12-02 16:06:40 +0000136 ("parse-unsupported", po::bool_switch()->default_value(false),
Sadik Armagana9c2ce12020-07-14 10:02:22 +0100137 "Add unsupported operators as stand-in layers (where supported by parser)")
138 ("infer-output-shape", po::bool_switch()->default_value(false),
139 "Infers output tensor shape from input tensor shape and validate where applicable (where supported by "
Sadik Armagana25886e2020-09-15 17:17:08 +0100140 "parser)")
Sadik Armagan283a8b42020-09-22 14:35:19 +0100141 ("enable-fast-math", po::bool_switch()->default_value(false),
Sadik Armagana25886e2020-09-15 17:17:08 +0100142 "Enable fast_math computation of Convolution2D operator where applicable (where supported by backend)");
telsoa01c577f2c2018-08-31 09:22:23 +0100143 }
144 catch (const std::exception& e)
145 {
146 // Coverity points out that default_value(...) can throw a bad_lexical_cast,
147 // and that desc.add_options() can throw boost::io::too_few_args.
148 // They really won't in any of these cases.
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +0100149 ARMNN_ASSERT_MSG(false, "Caught unexpected exception");
Derek Lamberti08446972019-11-26 16:38:31 +0000150 ARMNN_LOG(fatal) << "Fatal internal error: " << e.what();
telsoa01c577f2c2018-08-31 09:22:23 +0100151 return EXIT_FAILURE;
152 }
153
154 // Parses the command-line.
155 po::variables_map vm;
156 try
157 {
158 po::store(po::parse_command_line(argc, argv, desc), vm);
159
160 if (CheckOption(vm, "help") || argc <= 1)
161 {
162 std::cout << "Executes a neural network model using the provided input tensor. " << std::endl;
163 std::cout << "Prints the resulting output tensor." << std::endl;
164 std::cout << std::endl;
165 std::cout << desc << std::endl;
166 return EXIT_SUCCESS;
167 }
168
169 po::notify(vm);
170 }
171 catch (const po::error& e)
172 {
173 std::cerr << e.what() << std::endl << std::endl;
174 std::cerr << desc << std::endl;
175 return EXIT_FAILURE;
176 }
177
178 // Get the value of the switch arguments.
179 bool concurrent = vm["concurrent"].as<bool>();
180 bool enableProfiling = vm["event-based-profiling"].as<bool>();
Andre Ghattas23ae2ea2019-08-07 12:18:38 +0100181 bool enableLayerDetails = vm["visualize-optimized-model"].as<bool>();
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000182 bool enableBf16TurboMode = vm["bf16-turbo-mode"].as<bool>();
Ruomei Yan2fcce082019-04-02 16:47:34 +0100183 bool enableFp16TurboMode = vm["fp16-turbo-mode"].as<bool>();
Narumol Prangnawarat610256f2019-06-26 15:10:46 +0100184 bool quantizeInput = vm["quantize-input"].as<bool>();
Georgios Pinitas50311ba2020-02-18 13:25:23 +0000185 bool dequantizeOutput = vm["dequantize-output"].as<bool>();
Matthew Jackson54658b92019-08-27 15:35:59 +0100186 bool printIntermediate = vm["print-intermediate-layers"].as<bool>();
Jim Flynn4951b8c2019-10-03 10:04:30 -0700187 bool enableExternalProfiling = vm["enable-external-profiling"].as<bool>();
188 bool fileOnlyExternalProfiling = vm["file-only-external-profiling"].as<bool>();
Derek Lamberti132563c2019-12-02 16:06:40 +0000189 bool parseUnsupported = vm["parse-unsupported"].as<bool>();
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100190 bool timelineEnabled = vm["timeline-profiling"].as<bool>();
Sadik Armagana9c2ce12020-07-14 10:02:22 +0100191 bool inferOutputShape = vm["infer-output-shape"].as<bool>();
Sadik Armagan283a8b42020-09-22 14:35:19 +0100192 bool enableFastMath = vm["enable-fast-math"].as<bool>();
Derek Lamberti132563c2019-12-02 16:06:40 +0000193
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000194 if (enableBf16TurboMode && enableFp16TurboMode)
195 {
196 ARMNN_LOG(fatal) << "BFloat16 and Float16 turbo mode cannot be enabled at the same time.";
197 return EXIT_FAILURE;
198 }
199
Finn Williamsd7fcafa2020-04-23 17:55:18 +0100200 // Create runtime
201 armnn::IRuntime::CreationOptions options;
202 options.m_EnableGpuProfiling = enableProfiling;
203 options.m_DynamicBackendsPath = dynamicBackendsPath;
204 options.m_ProfilingOptions.m_EnableProfiling = enableExternalProfiling;
205 options.m_ProfilingOptions.m_IncomingCaptureFile = incomingCaptureFile;
206 options.m_ProfilingOptions.m_OutgoingCaptureFile = outgoingCaptureFile;
207 options.m_ProfilingOptions.m_FileOnly = fileOnlyExternalProfiling;
208 options.m_ProfilingOptions.m_CapturePeriod = counterCapturePeriod;
209 options.m_ProfilingOptions.m_FileFormat = fileFormat;
210 options.m_ProfilingOptions.m_TimelineEnabled = timelineEnabled;
211
212 if (timelineEnabled && !enableExternalProfiling)
213 {
214 ARMNN_LOG(fatal) << "Timeline profiling requires external profiling to be turned on";
215 return EXIT_FAILURE;
216 }
telsoa01c577f2c2018-08-31 09:22:23 +0100217
218 // Check whether we have to load test cases from a file.
219 if (CheckOption(vm, "test-cases"))
220 {
221 // Check that the file exists.
Francis Murtagh532a29d2020-06-29 11:50:01 +0100222 if (!fs::exists(testCasesFile))
telsoa01c577f2c2018-08-31 09:22:23 +0100223 {
Derek Lamberti08446972019-11-26 16:38:31 +0000224 ARMNN_LOG(fatal) << "Given file \"" << testCasesFile << "\" does not exist";
telsoa01c577f2c2018-08-31 09:22:23 +0100225 return EXIT_FAILURE;
226 }
227
228 // Parse CSV file and extract test cases
229 armnnUtils::CsvReader reader;
230 std::vector<armnnUtils::CsvRow> testCases = reader.ParseFile(testCasesFile);
231
232 // Check that there is at least one test case to run
233 if (testCases.empty())
234 {
Derek Lamberti08446972019-11-26 16:38:31 +0000235 ARMNN_LOG(fatal) << "Given file \"" << testCasesFile << "\" has no test cases";
telsoa01c577f2c2018-08-31 09:22:23 +0100236 return EXIT_FAILURE;
237 }
telsoa01c577f2c2018-08-31 09:22:23 +0100238 // Create runtime
telsoa01c577f2c2018-08-31 09:22:23 +0100239 std::shared_ptr<armnn::IRuntime> runtime(armnn::IRuntime::Create(options));
240
241 const std::string executableName("ExecuteNetwork");
242
243 // Check whether we need to run the test cases concurrently
244 if (concurrent)
245 {
246 std::vector<std::future<int>> results;
247 results.reserve(testCases.size());
248
249 // Run each test case in its own thread
250 for (auto& testCase : testCases)
251 {
252 testCase.values.insert(testCase.values.begin(), executableName);
Nina Drozd549ae372018-09-10 14:26:44 +0100253 results.push_back(std::async(std::launch::async, RunCsvTest, std::cref(testCase), std::cref(runtime),
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000254 enableProfiling, enableFp16TurboMode, enableBf16TurboMode, thresholdTime,
Sadik Armagana9c2ce12020-07-14 10:02:22 +0100255 printIntermediate, enableLayerDetails, parseUnsupported,
Sadik Armagana25886e2020-09-15 17:17:08 +0100256 inferOutputShape, enableFastMath));
telsoa01c577f2c2018-08-31 09:22:23 +0100257 }
258
259 // Check results
260 for (auto& result : results)
261 {
262 if (result.get() != EXIT_SUCCESS)
263 {
264 return EXIT_FAILURE;
265 }
266 }
267 }
268 else
269 {
270 // Run tests sequentially
271 for (auto& testCase : testCases)
272 {
273 testCase.values.insert(testCase.values.begin(), executableName);
Matthew Jackson54658b92019-08-27 15:35:59 +0100274 if (RunCsvTest(testCase, runtime, enableProfiling,
Narumol Prangnawaratd8cc8112020-03-24 13:54:05 +0000275 enableFp16TurboMode, enableBf16TurboMode, thresholdTime, printIntermediate,
Sadik Armagana25886e2020-09-15 17:17:08 +0100276 enableLayerDetails, parseUnsupported, inferOutputShape, enableFastMath) != EXIT_SUCCESS)
telsoa01c577f2c2018-08-31 09:22:23 +0100277 {
278 return EXIT_FAILURE;
279 }
280 }
281 }
282
283 return EXIT_SUCCESS;
284 }
285 else // Run single test
286 {
Aron Virginas-Tar382e21c2019-01-22 14:10:39 +0000287 // Get the preferred order of compute devices. If none are specified, default to using CpuRef
288 const std::string computeOption("compute");
Matteo Martincigh00dda4a2019-08-14 11:42:30 +0100289 std::vector<std::string> computeDevicesAsStrings =
290 CheckOption(vm, computeOption.c_str()) ?
291 vm[computeOption].as<std::vector<std::string>>() :
292 std::vector<std::string>();
Matteo Martincigh067112f2018-10-29 11:01:09 +0000293 std::vector<armnn::BackendId> computeDevices(computeDevicesAsStrings.begin(), computeDevicesAsStrings.end());
telsoa01c577f2c2018-08-31 09:22:23 +0100294
295 // Remove duplicates from the list of compute devices.
296 RemoveDuplicateDevices(computeDevices);
297
alered01a7227ac2020-05-07 14:58:29 +0100298#if defined(ARMCOMPUTECL_ENABLED)
299 std::shared_ptr<armnn::IGpuAccTunedParameters> tuned_params;
300
301 if (tuningPath != "")
302 {
303 if (tuningLevel != 0)
304 {
305 RunCLTuning(tuningPath, tuningLevel, modelFormat, inputTensorShapes, computeDevices,
306 dynamicBackendsPath, modelPath, inputNames, inputTensorDataFilePaths, inputTypes, quantizeInput,
307 outputTypes, outputNames, outputTensorFiles, dequantizeOutput, enableProfiling,
308 enableFp16TurboMode, enableBf16TurboMode, thresholdTime, printIntermediate, subgraphId,
Sadik Armagana25886e2020-09-15 17:17:08 +0100309 enableLayerDetails, parseUnsupported, inferOutputShape, enableFastMath);
alered01a7227ac2020-05-07 14:58:29 +0100310 }
311 ARMNN_LOG(info) << "Using tuning params: " << tuningPath << "\n";
312 options.m_BackendOptions.emplace_back(
313 armnn::BackendOptions
314 {
315 "GpuAcc",
316 {
317 {"TuningLevel", 0},
318 {"TuningFile", tuningPath.c_str()},
319 {"KernelProfilingEnabled", enableProfiling}
320 }
321 }
322 );
323 }
324#endif
telsoa01c577f2c2018-08-31 09:22:23 +0100325 try
326 {
327 CheckOptionDependencies(vm);
328 }
329 catch (const po::error& e)
330 {
331 std::cerr << e.what() << std::endl << std::endl;
332 std::cerr << desc << std::endl;
333 return EXIT_FAILURE;
334 }
Colm Donelanb682d842019-10-16 12:24:20 +0100335 // Create runtime
Colm Donelanb682d842019-10-16 12:24:20 +0100336 std::shared_ptr<armnn::IRuntime> runtime(armnn::IRuntime::Create(options));
Aron Virginas-Tarc82c8732019-10-24 17:07:43 +0100337
alered01a7227ac2020-05-07 14:58:29 +0100338 return RunTest(modelFormat, inputTensorShapes, computeDevices, dynamicBackendsPath, modelPath,
339 inputNames, inputTensorDataFilePaths, inputTypes, quantizeInput, outputTypes, outputNames,
340 outputTensorFiles, dequantizeOutput, enableProfiling, enableFp16TurboMode, enableBf16TurboMode,
Sadik Armagana9c2ce12020-07-14 10:02:22 +0100341 thresholdTime, printIntermediate, subgraphId, enableLayerDetails, parseUnsupported, inferOutputShape,
Sadik Armagana25886e2020-09-15 17:17:08 +0100342 enableFastMath, iterations, runtime);
telsoa014fcda012018-03-09 14:13:49 +0000343 }
344}