blob: ccf80648fef2a00168d9223495952c610945c76f [file] [log] [blame]
Jan Eilers45274902020-10-15 18:34:43 +01001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "ExecuteNetworkParams.hpp"
7
8#include "NetworkExecutionUtils/NetworkExecutionUtils.hpp"
9#include <InferenceModel.hpp>
10#include <armnn/Logging.hpp>
11
12#include <fmt/format.h>
13
14bool IsModelBinary(const std::string& modelFormat)
15{
16 // Parse model binary flag from the model-format string we got from the command-line
17 if (modelFormat.find("binary") != std::string::npos)
18 {
19 return true;
20 }
21 else if (modelFormat.find("txt") != std::string::npos || modelFormat.find("text") != std::string::npos)
22 {
23 return false;
24 }
25 else
26 {
27 throw armnn::InvalidArgumentException(fmt::format("Unknown model format: '{}'. "
28 "Please include 'binary' or 'text'",
29 modelFormat));
30 }
31}
32
33void CheckModelFormat(const std::string& modelFormat)
34{
35 // Forward to implementation based on the parser type
36 if (modelFormat.find("armnn") != std::string::npos)
37 {
38#if defined(ARMNN_SERIALIZER)
39#else
40 throw armnn::InvalidArgumentException("Can't run model in armnn format without a "
41 "built with serialization support.");
42#endif
43 }
44 else if (modelFormat.find("caffe") != std::string::npos)
45 {
46#if defined(ARMNN_CAFFE_PARSER)
47#else
48 throw armnn::InvalidArgumentException("Can't run model in caffe format without a "
49 "built with Caffe parser support.");
50#endif
51 }
52 else if (modelFormat.find("onnx") != std::string::npos)
53 {
54#if defined(ARMNN_ONNX_PARSER)
55#else
56 throw armnn::InvalidArgumentException("Can't run model in onnx format without a "
57 "built with Onnx parser support.");
58#endif
59 }
60 else if (modelFormat.find("tensorflow") != std::string::npos)
61 {
62#if defined(ARMNN_TF_PARSER)
63#else
64 throw armnn::InvalidArgumentException("Can't run model in onnx format without a "
65 "built with Tensorflow parser support.");
66#endif
67 }
68 else if(modelFormat.find("tflite") != std::string::npos)
69 {
70#if defined(ARMNN_TF_LITE_PARSER)
71 if (!IsModelBinary(modelFormat))
72 {
73 throw armnn::InvalidArgumentException(fmt::format("Unknown model format: '{}'. Only 'binary' format "
74 "supported for tflite files",
75 modelFormat));
76 }
77#else
78 throw armnn::InvalidArgumentException("Can't run model in tflite format without a "
79 "built with Tensorflow Lite parser support.");
80#endif
81 }
82 else
83 {
84 throw armnn::InvalidArgumentException(fmt::format("Unknown model format: '{}'. "
85 "Please include 'caffe', 'tensorflow', 'tflite' or 'onnx'",
86 modelFormat));
87 }
88}
89
90void CheckClTuningParameter(const int& tuningLevel,
91 const std::string& tuningPath,
92 const std::vector<armnn::BackendId> computeDevices)
93{
94 if (!tuningPath.empty())
95 {
96 if(tuningLevel == 0)
97 {
98 ARMNN_LOG(info) << "Using cl tuning file: " << tuningPath << "\n";
99 if(!ValidatePath(tuningPath, true))
100 {
101 throw armnn::InvalidArgumentException("The tuning path is not valid");
102 }
103 }
104 else if ((1 <= tuningLevel) && (tuningLevel <= 3))
105 {
106 ARMNN_LOG(info) << "Starting execution to generate a cl tuning file: " << tuningPath << "\n"
107 << "Tuning level in use: " << tuningLevel << "\n";
108 }
109 else if ((0 < tuningLevel) || (tuningLevel > 3))
110 {
111 throw armnn::InvalidArgumentException(fmt::format("The tuning level {} is not valid.", tuningLevel));
112 }
113
114 // Ensure that a GpuAcc is enabled. Otherwise no tuning data are used or genereted
115 // Only warn if it's not enabled
116 auto it = std::find(computeDevices.begin(), computeDevices.end(), "GpuAcc");
117 if (it == computeDevices.end())
118 {
119 ARMNN_LOG(warning) << "To use Cl Tuning the compute device GpuAcc needs to be active.";
120 }
121 }
122
123
124}
125
126void ExecuteNetworkParams::ValidateParams()
127{
Francis Murtaghbf18a262020-10-27 15:20:40 +0000128 if (m_DynamicBackendsPath=="")
Jan Eilers45274902020-10-15 18:34:43 +0100129 {
Francis Murtaghbf18a262020-10-27 15:20:40 +0000130 // Check compute devices are valid unless they are dynamically loaded at runtime
131 std::string invalidBackends;
132 if (!CheckRequestedBackendsAreValid(m_ComputeDevices, armnn::Optional<std::string&>(invalidBackends)))
133 {
134 throw armnn::InvalidArgumentException(
135 fmt::format("Some of the requested compute devices are invalid. "
136 "\nInvalid devices: {} \nAvailable devices are: {}",
137 invalidBackends,
138 armnn::BackendRegistryInstance().GetBackendIdsAsString()));
139 }
Jan Eilers45274902020-10-15 18:34:43 +0100140 }
141
142 CheckClTuningParameter(m_TuningLevel, m_TuningPath, m_ComputeDevices);
143
144 // Check turbo modes
145 if (m_EnableBf16TurboMode && m_EnableFp16TurboMode)
146 {
147 throw armnn::InvalidArgumentException("BFloat16 and Float16 turbo mode cannot be enabled at the same time.");
148 }
149
150 m_IsModelBinary = IsModelBinary(m_ModelFormat);
151
152 CheckModelFormat(m_ModelFormat);
153
154 // Check input tensor shapes
155 if ((m_InputTensorShapes.size() != 0) &&
156 (m_InputTensorShapes.size() != m_InputNames.size()))
157 {
158 throw armnn::InvalidArgumentException("input-name and input-tensor-shape must "
159 "have the same amount of elements.");
160 }
161
162 if (m_InputTensorDataFilePaths.size() != 0)
163 {
164 if (!ValidatePaths(m_InputTensorDataFilePaths, true))
165 {
166 throw armnn::InvalidArgumentException("One or more input data file paths are not valid.");
167 }
168
169 if (m_InputTensorDataFilePaths.size() != m_InputNames.size())
170 {
171 throw armnn::InvalidArgumentException("input-name and input-tensor-data must have "
172 "the same amount of elements.");
173 }
174 }
175
176 if ((m_OutputTensorFiles.size() != 0) &&
177 (m_OutputTensorFiles.size() != m_OutputNames.size()))
178 {
179 throw armnn::InvalidArgumentException("output-name and write-outputs-to-file must have the "
180 "same amount of elements.");
181 }
182
183 if (m_InputTypes.size() == 0)
184 {
185 //Defaults the value of all inputs to "float"
186 m_InputTypes.assign(m_InputNames.size(), "float");
187 }
188 else if ((m_InputTypes.size() != 0) &&
189 (m_InputTypes.size() != m_InputNames.size()))
190 {
191 throw armnn::InvalidArgumentException("input-name and input-type must have the same amount of elements.");
192 }
193
194 if (m_OutputTypes.size() == 0)
195 {
196 //Defaults the value of all outputs to "float"
197 m_OutputTypes.assign(m_OutputNames.size(), "float");
198 }
199 else if ((m_OutputTypes.size() != 0) &&
200 (m_OutputTypes.size() != m_OutputNames.size()))
201 {
202 throw armnn::InvalidArgumentException("output-name and output-type must have the same amount of elements.");
203 }
204
205 // Check that threshold time is not less than zero
206 if (m_ThresholdTime < 0)
207 {
208 throw armnn::InvalidArgumentException("Threshold time supplied as a command line argument is less than zero.");
209 }
210
211 // Warn if ExecuteNetwork will generate dummy input data
212 if (m_GenerateTensorData)
213 {
214 ARMNN_LOG(warning) << "No input files provided, input tensors will be filled with 0s.";
215 }
216}