blob: 1c1fa100316f60f59be7665f997f264edec2432b [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. 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);
18 armnnUtils::ConfigureLogging(boost::log::core::get().get(), true, true, level);
19
20 std::string testCasesFile;
21
22 std::string modelFormat;
23 std::string modelPath;
Ferran Balaguerc602f292019-02-08 17:09:55 +000024 std::string inputNames;
25 std::string inputTensorShapes;
26 std::string inputTensorDataFilePaths;
27 std::string outputNames;
28 std::string inputTypes;
Éanna Ó Catháinb3d481a2019-02-26 11:26:24 +000029 std::string outputTypes;
Matteo Martincigh00dda4a2019-08-14 11:42:30 +010030 std::string dynamicBackendsPath;
Sadik Armagan77086282019-09-02 11:46:28 +010031 std::string outputTensorFiles;
telsoa01c577f2c2018-08-31 09:22:23 +010032
Jim Flynn4951b8c2019-10-03 10:04:30 -070033 // external profiling parameters
34 std::string outgoingCaptureFile;
35 std::string incomingCaptureFile;
36 uint32_t counterCapturePeriod;
37
James Conroy7b4886f2019-04-11 10:23:58 +010038 double thresholdTime = 0.0;
39
telsoa01c577f2c2018-08-31 09:22:23 +010040 size_t subgraphId = 0;
41
Matthew Jackson07882f12019-09-05 15:55:55 +010042 const std::string backendsMessage = "REQUIRED: Which device to run layers on by default. Possible choices: "
Aron Virginas-Tar5cc8e562018-10-23 15:14:46 +010043 + armnn::BackendRegistryInstance().GetBackendIdsAsString();
44
telsoa01c577f2c2018-08-31 09:22:23 +010045 po::options_description desc("Options");
46 try
47 {
48 desc.add_options()
49 ("help", "Display usage information")
Matthew Jackson07882f12019-09-05 15:55:55 +010050 ("compute,c", po::value<std::vector<std::string>>()->multitoken()->required(),
51 backendsMessage.c_str())
telsoa01c577f2c2018-08-31 09:22:23 +010052 ("test-cases,t", po::value(&testCasesFile), "Path to a CSV file containing test cases to run. "
53 "If set, further parameters -- with the exception of compute device and concurrency -- will be ignored, "
54 "as they are expected to be defined in the file for each test in particular.")
55 ("concurrent,n", po::bool_switch()->default_value(false),
56 "Whether or not the test cases should be executed in parallel")
Matteo Martincigh49124022019-01-11 13:25:59 +000057 ("model-format,f", po::value(&modelFormat)->required(),
Aron Virginas-Tar64e4ccb2019-02-12 11:27:53 +000058 "armnn-binary, caffe-binary, caffe-text, onnx-binary, onnx-text, tflite-binary, tensorflow-binary or "
59 "tensorflow-text.")
60 ("model-path,m", po::value(&modelPath)->required(), "Path to model file, e.g. .armnn, .caffemodel, "
61 ".prototxt, .tflite, .onnx")
Matteo Martincigh00dda4a2019-08-14 11:42:30 +010062 ("dynamic-backends-path,b", po::value(&dynamicBackendsPath),
63 "Path where to load any available dynamic backend from. "
64 "If left empty (the default), dynamic backends will not be used.")
Ferran Balaguerc602f292019-02-08 17:09:55 +000065 ("input-name,i", po::value(&inputNames),
66 "Identifier of the input tensors in the network separated by comma.")
telsoa01c577f2c2018-08-31 09:22:23 +010067 ("subgraph-number,x", po::value<size_t>(&subgraphId)->default_value(0), "Id of the subgraph to be executed."
68 "Defaults to 0")
Ferran Balaguerc602f292019-02-08 17:09:55 +000069 ("input-tensor-shape,s", po::value(&inputTensorShapes),
Francis Murtagh1555cbd2019-10-08 14:47:46 +010070 "The shape of the input tensors in the network as a flat array of integers separated by comma."
71 "Several shapes can be passed by separating them with a colon (:)."
telsoa01c577f2c2018-08-31 09:22:23 +010072 "This parameter is optional, depending on the network.")
Ferran Balaguerc602f292019-02-08 17:09:55 +000073 ("input-tensor-data,d", po::value(&inputTensorDataFilePaths),
74 "Path to files containing the input data as a flat array separated by whitespace. "
Francis Murtagh1555cbd2019-10-08 14:47:46 +010075 "Several paths can be passed by separating them with a comma.")
Ferran Balaguerc602f292019-02-08 17:09:55 +000076 ("input-type,y",po::value(&inputTypes), "The type of the input tensors in the network separated by comma. "
77 "If unset, defaults to \"float\" for all defined inputs. "
Éanna Ó Catháinb3d481a2019-02-26 11:26:24 +000078 "Accepted values (float, int or qasymm8)")
Narumol Prangnawarat610256f2019-06-26 15:10:46 +010079 ("quantize-input,q",po::bool_switch()->default_value(false),
80 "If this option is enabled, all float inputs will be quantized to qasymm8. "
81 "If unset, default to not quantized. "
82 "Accepted values (true or false)")
Éanna Ó Catháinb3d481a2019-02-26 11:26:24 +000083 ("output-type,z",po::value(&outputTypes),
84 "The type of the output tensors in the network separated by comma. "
85 "If unset, defaults to \"float\" for all defined outputs. "
86 "Accepted values (float, int or qasymm8).")
Ferran Balaguerc602f292019-02-08 17:09:55 +000087 ("output-name,o", po::value(&outputNames),
88 "Identifier of the output tensors in the network separated by comma.")
Sadik Armagan77086282019-09-02 11:46:28 +010089 ("write-outputs-to-file,w", po::value(&outputTensorFiles),
90 "Comma-separated list of output file paths keyed with the binding-id of the output slot. "
91 "If left empty (the default), the output tensors will not be written to a file.")
telsoa01c577f2c2018-08-31 09:22:23 +010092 ("event-based-profiling,e", po::bool_switch()->default_value(false),
Ruomei Yan2fcce082019-04-02 16:47:34 +010093 "Enables built in profiler. If unset, defaults to off.")
Andre Ghattas23ae2ea2019-08-07 12:18:38 +010094 ("visualize-optimized-model,v", po::bool_switch()->default_value(false),
95 "Enables built optimized model visualizer. If unset, defaults to off.")
Ruomei Yan2fcce082019-04-02 16:47:34 +010096 ("fp16-turbo-mode,h", po::bool_switch()->default_value(false), "If this option is enabled, FP32 layers, "
James Conroy7b4886f2019-04-11 10:23:58 +010097 "weights and biases will be converted to FP16 where the backend supports it")
98 ("threshold-time,r", po::value<double>(&thresholdTime)->default_value(0.0),
99 "Threshold time is the maximum allowed time for inference measured in milliseconds. If the actual "
100 "inference time is greater than the threshold time, the test will fail. By default, no threshold "
Matthew Jackson54658b92019-08-27 15:35:59 +0100101 "time is used.")
102 ("print-intermediate-layers,p", po::bool_switch()->default_value(false),
Jim Flynn4951b8c2019-10-03 10:04:30 -0700103 "If this option is enabled, the output of every graph layer will be printed.")
104 ("enable-external-profiling,a", po::bool_switch()->default_value(false),
105 "If enabled external profiling will be switched on")
106 ("outgoing-capture-file,j", po::value(&outgoingCaptureFile),
107 "If specified the outgoing external profiling packets will be captured in this binary file")
108 ("incoming-capture-file,k", po::value(&incomingCaptureFile),
109 "If specified the incoming external profiling packets will be captured in this binary file")
110 ("file-only-external-profiling,g", po::bool_switch()->default_value(false),
111 "If enabled then the 'file-only' test mode of external profiling will be enabled")
112 ("counter-capture-period,u", po::value<uint32_t>(&counterCapturePeriod)->default_value(150u),
113 "If profiling is enabled in 'file-only' mode this is the capture period that will be used in the test");
telsoa01c577f2c2018-08-31 09:22:23 +0100114 }
115 catch (const std::exception& e)
116 {
117 // Coverity points out that default_value(...) can throw a bad_lexical_cast,
118 // and that desc.add_options() can throw boost::io::too_few_args.
119 // They really won't in any of these cases.
120 BOOST_ASSERT_MSG(false, "Caught unexpected exception");
121 BOOST_LOG_TRIVIAL(fatal) << "Fatal internal error: " << e.what();
122 return EXIT_FAILURE;
123 }
124
125 // Parses the command-line.
126 po::variables_map vm;
127 try
128 {
129 po::store(po::parse_command_line(argc, argv, desc), vm);
130
131 if (CheckOption(vm, "help") || argc <= 1)
132 {
133 std::cout << "Executes a neural network model using the provided input tensor. " << std::endl;
134 std::cout << "Prints the resulting output tensor." << std::endl;
135 std::cout << std::endl;
136 std::cout << desc << std::endl;
137 return EXIT_SUCCESS;
138 }
139
140 po::notify(vm);
141 }
142 catch (const po::error& e)
143 {
144 std::cerr << e.what() << std::endl << std::endl;
145 std::cerr << desc << std::endl;
146 return EXIT_FAILURE;
147 }
148
149 // Get the value of the switch arguments.
150 bool concurrent = vm["concurrent"].as<bool>();
151 bool enableProfiling = vm["event-based-profiling"].as<bool>();
Andre Ghattas23ae2ea2019-08-07 12:18:38 +0100152 bool enableLayerDetails = vm["visualize-optimized-model"].as<bool>();
Ruomei Yan2fcce082019-04-02 16:47:34 +0100153 bool enableFp16TurboMode = vm["fp16-turbo-mode"].as<bool>();
Narumol Prangnawarat610256f2019-06-26 15:10:46 +0100154 bool quantizeInput = vm["quantize-input"].as<bool>();
Matthew Jackson54658b92019-08-27 15:35:59 +0100155 bool printIntermediate = vm["print-intermediate-layers"].as<bool>();
Jim Flynn4951b8c2019-10-03 10:04:30 -0700156 bool enableExternalProfiling = vm["enable-external-profiling"].as<bool>();
157 bool fileOnlyExternalProfiling = vm["file-only-external-profiling"].as<bool>();
telsoa01c577f2c2018-08-31 09:22:23 +0100158
159 // Check whether we have to load test cases from a file.
160 if (CheckOption(vm, "test-cases"))
161 {
162 // Check that the file exists.
163 if (!boost::filesystem::exists(testCasesFile))
164 {
165 BOOST_LOG_TRIVIAL(fatal) << "Given file \"" << testCasesFile << "\" does not exist";
166 return EXIT_FAILURE;
167 }
168
169 // Parse CSV file and extract test cases
170 armnnUtils::CsvReader reader;
171 std::vector<armnnUtils::CsvRow> testCases = reader.ParseFile(testCasesFile);
172
173 // Check that there is at least one test case to run
174 if (testCases.empty())
175 {
176 BOOST_LOG_TRIVIAL(fatal) << "Given file \"" << testCasesFile << "\" has no test cases";
177 return EXIT_FAILURE;
178 }
179
180 // Create runtime
181 armnn::IRuntime::CreationOptions options;
Nina Drozd549ae372018-09-10 14:26:44 +0100182 options.m_EnableGpuProfiling = enableProfiling;
Jim Flynn4951b8c2019-10-03 10:04:30 -0700183 options.m_ProfilingOptions.m_EnableProfiling = enableExternalProfiling;
184 options.m_ProfilingOptions.m_IncomingCaptureFile = incomingCaptureFile;
185 options.m_ProfilingOptions.m_OutgoingCaptureFile = outgoingCaptureFile;
186 options.m_ProfilingOptions.m_FileOnly = fileOnlyExternalProfiling;
187 options.m_ProfilingOptions.m_CapturePeriod = counterCapturePeriod;
Nina Drozd549ae372018-09-10 14:26:44 +0100188
telsoa01c577f2c2018-08-31 09:22:23 +0100189 std::shared_ptr<armnn::IRuntime> runtime(armnn::IRuntime::Create(options));
190
191 const std::string executableName("ExecuteNetwork");
192
193 // Check whether we need to run the test cases concurrently
194 if (concurrent)
195 {
196 std::vector<std::future<int>> results;
197 results.reserve(testCases.size());
198
199 // Run each test case in its own thread
200 for (auto& testCase : testCases)
201 {
202 testCase.values.insert(testCase.values.begin(), executableName);
Nina Drozd549ae372018-09-10 14:26:44 +0100203 results.push_back(std::async(std::launch::async, RunCsvTest, std::cref(testCase), std::cref(runtime),
Andre Ghattas23ae2ea2019-08-07 12:18:38 +0100204 enableProfiling, enableFp16TurboMode, thresholdTime, printIntermediate,
205 enableLayerDetails));
telsoa01c577f2c2018-08-31 09:22:23 +0100206 }
207
208 // Check results
209 for (auto& result : results)
210 {
211 if (result.get() != EXIT_SUCCESS)
212 {
213 return EXIT_FAILURE;
214 }
215 }
216 }
217 else
218 {
219 // Run tests sequentially
220 for (auto& testCase : testCases)
221 {
222 testCase.values.insert(testCase.values.begin(), executableName);
Matthew Jackson54658b92019-08-27 15:35:59 +0100223 if (RunCsvTest(testCase, runtime, enableProfiling,
Andre Ghattas23ae2ea2019-08-07 12:18:38 +0100224 enableFp16TurboMode, thresholdTime, printIntermediate,
225 enableLayerDetails) != EXIT_SUCCESS)
telsoa01c577f2c2018-08-31 09:22:23 +0100226 {
227 return EXIT_FAILURE;
228 }
229 }
230 }
231
232 return EXIT_SUCCESS;
233 }
234 else // Run single test
235 {
Aron Virginas-Tar382e21c2019-01-22 14:10:39 +0000236 // Get the preferred order of compute devices. If none are specified, default to using CpuRef
237 const std::string computeOption("compute");
Matteo Martincigh00dda4a2019-08-14 11:42:30 +0100238 std::vector<std::string> computeDevicesAsStrings =
239 CheckOption(vm, computeOption.c_str()) ?
240 vm[computeOption].as<std::vector<std::string>>() :
241 std::vector<std::string>();
Matteo Martincigh067112f2018-10-29 11:01:09 +0000242 std::vector<armnn::BackendId> computeDevices(computeDevicesAsStrings.begin(), computeDevicesAsStrings.end());
telsoa01c577f2c2018-08-31 09:22:23 +0100243
244 // Remove duplicates from the list of compute devices.
245 RemoveDuplicateDevices(computeDevices);
246
telsoa01c577f2c2018-08-31 09:22:23 +0100247 try
248 {
249 CheckOptionDependencies(vm);
250 }
251 catch (const po::error& e)
252 {
253 std::cerr << e.what() << std::endl << std::endl;
254 std::cerr << desc << std::endl;
255 return EXIT_FAILURE;
256 }
257
Matteo Martincigh00dda4a2019-08-14 11:42:30 +0100258 return RunTest(modelFormat, inputTensorShapes, computeDevices, dynamicBackendsPath, modelPath, inputNames,
Narumol Prangnawarat610256f2019-06-26 15:10:46 +0100259 inputTensorDataFilePaths, inputTypes, quantizeInput, outputTypes, outputNames,
Sadik Armagan77086282019-09-02 11:46:28 +0100260 outputTensorFiles, enableProfiling, enableFp16TurboMode, thresholdTime, printIntermediate,
Andre Ghattas23ae2ea2019-08-07 12:18:38 +0100261 subgraphId, enableLayerDetails);
telsoa014fcda012018-03-09 14:13:49 +0000262 }
263}