blob: b850a65acfe0136118009fa3487d55fc10527e83 [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//
5#include "WorkloadData.hpp"
6
7#include "CpuTensorHandle.hpp"
telsoa014fcda012018-03-09 14:13:49 +00008
Matteo Martincigh21350152018-11-28 16:22:22 +00009#include <DataLayoutIndexed.hpp>
Matthew Bentham8800c002018-11-19 13:19:28 +000010
telsoa014fcda012018-03-09 14:13:49 +000011#include <algorithm>
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +000012#include <iomanip>
telsoa014fcda012018-03-09 14:13:49 +000013#include <string>
14#include <sstream>
telsoa014fcda012018-03-09 14:13:49 +000015
16#include <boost/format.hpp>
17
Matteo Martincigh21350152018-11-28 16:22:22 +000018using namespace armnnUtils;
19
telsoa014fcda012018-03-09 14:13:49 +000020namespace armnn
21{
22
23//---------------------------------------------------------------
24DataType GetBiasDataType(DataType inputDataType)
25{
26 switch (inputDataType)
27 {
telsoa01c577f2c2018-08-31 09:22:23 +010028 case DataType::Float16:
29 return DataType::Float16;
telsoa014fcda012018-03-09 14:13:49 +000030 case DataType::Float32:
31 return DataType::Float32;
32 case DataType::QuantisedAsymm8:
33 return DataType::Signed32;
34 default:
35 BOOST_ASSERT_MSG(false, "Invalid input data type");
36 return DataType::Float32;
37 }
38}
39
40namespace
41{
42
43//---------------------------------------------------------------
44//android ndk does not support std::to_string function.
45template <typename T>
46std::string to_string(T value)
47{
48 std::ostringstream os;
49 os << value;
50 return os.str();
51}
52
53//---------------------------------------------------------------
54void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName)
55{
56 if (!ptr)
57 {
58 throw InvalidArgumentException(descName + ": Invalid null pointer. The " +
59 paramName + " parameter must be set.");
60 }
61}
62
63//---------------------------------------------------------------
64void ValidateTensorShapesMatch(const TensorInfo& first,
65 const TensorInfo& second,
66 std::string const& descName,
67 std::string const& firstName,
68 std::string const& secondName)
69{
70 if (first.GetShape() != second.GetShape())
71 {
72 throw InvalidArgumentException(descName + ": "
73 + firstName + " & " + secondName + " must have identical shapes");
74 }
75}
76
77//---------------------------------------------------------------
Sadik Armaganeff363d2019-04-05 15:25:46 +010078void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000079{
Sadik Armaganeff363d2019-04-05 15:25:46 +010080 if (workloadInfo.m_InputTensorInfos.size() != expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000081 {
82 throw InvalidArgumentException(descName +
Sadik Armaganeff363d2019-04-05 15:25:46 +010083 ": Requires exactly " + to_string(expectedSize) + "input(s). " +
telsoa014fcda012018-03-09 14:13:49 +000084 to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided.");
85 }
86}
87
88//---------------------------------------------------------------
Sadik Armaganeff363d2019-04-05 15:25:46 +010089void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000090{
Sadik Armaganeff363d2019-04-05 15:25:46 +010091 if (workloadInfo.m_OutputTensorInfos.size() != expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000092 {
93 throw InvalidArgumentException(descName +
Sadik Armaganeff363d2019-04-05 15:25:46 +010094 ": Requires exactly " + to_string(expectedSize) + " output(s). " +
telsoa014fcda012018-03-09 14:13:49 +000095 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
96 }
97}
98
99//---------------------------------------------------------------
100void ValidateTensorNumDimensions(const TensorInfo& tensor,
101 std::string const& descName,
102 unsigned int numDimensions,
103 std::string const& tensorName)
104{
105 if (tensor.GetNumDimensions() != numDimensions)
106 {
107 throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " +
108 to_string(tensor.GetNumDimensions()) + " dimensions for " +
109 tensorName + " tensor.");
110 }
111}
112
113//---------------------------------------------------------------
114void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
115 const std::string& descName, std::string const& tensorName)
116{
117 if (tensor.GetDataType() != dataType)
118 {
119 throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
120 GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
121 }
122}
123
124//---------------------------------------------------------------
125void ValidateBiasTensorQuantization(const TensorInfo& biasTensor, const TensorInfo& inputTensorInfo,
126 const TensorInfo& weightsTensorInfo, const std::string& descName)
127{
128 if (biasTensor.GetQuantizationOffset() != 0)
129 {
130 throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
131 to_string(biasTensor.GetQuantizationOffset()));
132 }
133 const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightsTensorInfo.GetQuantizationScale();
kevmay016c46dd32018-12-17 15:32:45 +0000134 if (std::abs(biasTensor.GetQuantizationScale() - expectedScale) > 0.00000001f)
telsoa014fcda012018-03-09 14:13:49 +0000135 {
136 // Print the float values with extra precision to see very small differences
137 std::stringstream msg;
138 msg << std::setprecision(10) << descName << ": Expected " << expectedScale <<
139 " quantization scale for bias tensor (the product of the input and weight scales), but got " <<
140 biasTensor.GetQuantizationScale();
141 throw InvalidArgumentException(msg.str());
142 }
143}
144
145//---------------------------------------------------------------
146void ValidateTensors(const std::vector<ITensorHandle*>& vec,
147 unsigned int numExpected,
148 const std::string& descName,
149 const std::string& varName)
150{
151 if (vec.empty() && numExpected > 0)
152 {
153 throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
154 }
155
156 for (unsigned int i = 0; i < numExpected; ++i)
157 {
158 if (!vec[i])
159 {
160 throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
161 }
162 }
163}
164
165//---------------------------------------------------------------
166void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
167 const TensorInfo& second,
168 const TensorInfo& output,
169 std::string const& descName,
170 std::string const& firstName,
171 std::string const& secondName)
172{
173 // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
174 // broadcasted.
175 if (first.GetNumDimensions() != second.GetNumDimensions())
176 {
177 throw InvalidArgumentException(descName + ": Tensors "
178 + firstName + " & " + secondName
179 + " must have the same number of dimensions in order to be broadcasted");
180 }
181 uint32_t numDims = first.GetNumDimensions();
182 std::vector<uint32_t> outputDims(numDims, 0u);
183 for (uint32_t i = 0; i < numDims; i++)
184 {
185 const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i];
186 const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1);
187 if (dimsNotEqual && dimsNotOne)
188 {
189 throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes");
190 }
191 outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]);
192 }
193 TensorShape broadcastShape = TensorShape(boost::numeric_cast<unsigned int>(outputDims.size()), outputDims.data());
194 if (broadcastShape != output.GetShape())
195 {
196 throw InvalidArgumentException(descName + ": The tensor shape resulting from adding "
197 + firstName + " & " + secondName
198 + " does not match the output shape");
199 }
200}
201
202//---------------------------------------------------------------
203/// Validates that the output tensor's quantization scale is greater than the product
204/// of the two input tensors' quantization scales. This is a requirement of the implementation of
205/// the quantized multiplication.
206void ValidateTensorQuantizationMultiplier(const TensorInfo& inputTensor1, const TensorInfo& inputTensor2,
207 const TensorInfo& outputTensorInfo, std::string const& descName,
208 const std::string& inputTensor1Name, const std::string& inputTensor2Name, const std::string& outputTensorName)
209{
210 if (outputTensorInfo.GetDataType() == DataType::QuantisedAsymm8)
211 {
212 if (outputTensorInfo.GetQuantizationScale() <=
213 inputTensor1.GetQuantizationScale() * inputTensor2.GetQuantizationScale())
214 {
215 std::stringstream msg;
216 msg << descName << ": Quantization scale of " << outputTensorName << " is not greater than " <<
217 "the product of the " << inputTensor1Name << " and " << inputTensor2Name << " tensors";
218 throw InvalidArgumentException(msg.str());
219 }
220 }
221}
222
Sadik Armaganeff363d2019-04-05 15:25:46 +0100223//---------------------------------------------------------------
224void ValidateDataTypes(const TensorInfo& info,
225 const std::vector<armnn::DataType>& supportedTypes,
226 std::string const& descName)
227{
228 auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
229 if (iterator == supportedTypes.end())
230 {
231 throw InvalidArgumentException(descName + ": " + " Tensor type is not supported.");
232 }
233}
234
telsoa014fcda012018-03-09 14:13:49 +0000235} //namespace
236
237void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
238 unsigned int numExpectedIn, unsigned int numExpectedOut) const
239{
240 ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
241 ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
242}
243
244//---------------------------------------------------------------
245void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
246{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100247 ValidateNumInputs(workloadInfo, "MemCopyQueueDescriptor", 1);
248 ValidateNumOutputs(workloadInfo, "MemCopyQueueDescriptor" , 1);
telsoa014fcda012018-03-09 14:13:49 +0000249
250 if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
251 {
252 throw InvalidArgumentException(boost::str(
253 boost::format("Number of input infos (%1%) does not match the number of output infos (%2%)")
254 % workloadInfo.m_InputTensorInfos.size() % workloadInfo.m_OutputTensorInfos.size()));
255 }
256
257 for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
258 {
259 if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
260 workloadInfo.m_OutputTensorInfos[i].GetNumElements())
261 {
262 throw InvalidArgumentException(boost::str(
263 boost::format("Number of elements for tensor input and output %1% does not match")
264 % i ));
265 }
266 }
267
268 if (m_Inputs.size() != m_Outputs.size())
269 {
270 throw InvalidArgumentException(boost::str(
271 boost::format("Number of inputs (%1%) does not match the number of outputs (%2%)")
272 % m_Inputs.size() % m_Outputs.size()));
273 }
274
275 for (unsigned int i = 0; i < m_Inputs.size(); ++i)
276 {
277 if (!m_Inputs[i])
278 {
279 throw InvalidArgumentException(boost::str(boost::format("Invalid null input %1%") % i));
280 }
281
282 if (!m_Outputs[i])
283 {
284 throw InvalidArgumentException(boost::str(boost::format("Invalid null output %1%") % i));
285 }
286 }
287}
288
289//---------------------------------------------------------------
290void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
291{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100292 ValidateNumInputs(workloadInfo, "ActivationQueueDescriptor", 1);
293 ValidateNumOutputs(workloadInfo, "ActivationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000294 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
295 workloadInfo.m_OutputTensorInfos[0],
296 "ActivationQueueDescriptor",
297 "input",
298 "output");
299}
300
301//---------------------------------------------------------------
302void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
303{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100304 ValidateNumInputs(workloadInfo, "SoftmaxQueueDescriptor", 1);
305 ValidateNumOutputs(workloadInfo, "SoftmaxQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000306
307 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
308 workloadInfo.m_OutputTensorInfos[0],
309 "SoftmaxQueueDescriptor",
310 "input",
311 "output");
312}
313
314//---------------------------------------------------------------
315void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
316{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100317 ValidateNumInputs(workloadInfo, "SplitterQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000318
319 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
320 {
321 throw InvalidArgumentException("SplitterQueueDescriptor: At least one output needs to be provided.");
322 }
323
324 if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
325 {
326 throw InvalidArgumentException(
327 "SplitterQueueDescriptor: Number of split windows "
328 "has to match number of workloadInfo.m_OutputTensorInfos. "
329 "Number of windows: " +
330 to_string(m_ViewOrigins.size()) +
331 ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
332 }
333
telsoa01c577f2c2018-08-31 09:22:23 +0100334 //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
telsoa014fcda012018-03-09 14:13:49 +0000335 std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
336 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
337 {
telsoa01c577f2c2018-08-31 09:22:23 +0100338 //Checks that the dimensionality of input is same as the split windows.
telsoa014fcda012018-03-09 14:13:49 +0000339 ViewOrigin const& e = m_ViewOrigins[w];
340 if (e.m_Origin.size() != inputDims)
341 {
342 throw InvalidArgumentException("SplitterQueueDescriptor: Window origin have to "
343 "have the same dimensionality as the input tensor. "
344 "Window origin (index: " +
345 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
346 " dimensions, the input "
347 "tensor has " +
348 to_string(inputDims) + " dimensions.");
349 }
350 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
351 {
352 if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
353 workloadInfo.m_InputTensorInfos[0].GetShape()[i])
354 {
355 throw InvalidArgumentException("SplitterQueueDescriptor: Window extent coordinates have to "
356 "be smaller or equal than the size of the input in that coord.");
357 }
358 }
359 }
360}
361
362//---------------------------------------------------------------
363void MergerQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
364{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100365 ValidateNumOutputs(workloadInfo, "MergerQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000366
367 if (m_Inputs.size() <= 0)
368 {
369 throw InvalidArgumentException("MergerQueueDescriptor: At least one input needs to be provided.");
370 }
371 if (m_Outputs.size() <= 0)
372 {
373 throw InvalidArgumentException("MergerQueueDescriptor: At least one output needs to be provided.");
374 }
375
376 if (workloadInfo.m_InputTensorInfos.size() <= 0)
377 {
378 throw InvalidArgumentException("MergerQueueDescriptor: At least one TensorInfo input needs to be provided.");
379 }
380 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
381 {
382 throw InvalidArgumentException("MergerQueueDescriptor: At least one TensorInfo output needs to be provided.");
383 }
384
Nikhil Raj8599a412018-11-19 14:51:07 +0000385 if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
386 {
387 throw InvalidArgumentException("Invalid Concatenation Axis provided");
388 }
389
390 if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
391 {
392 return;
393 }
394
telsoa014fcda012018-03-09 14:13:49 +0000395 if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
396 {
397 throw InvalidArgumentException(
398 "MergerQueueDescriptor: Number of split windows "
399 "has to match number of workloadInfo.m_InputTensorInfos. "
400 "Number of windows: " +
401 to_string(m_ViewOrigins.size()) +
402 ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
403 }
404
telsoa01c577f2c2018-08-31 09:22:23 +0100405 //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
telsoa014fcda012018-03-09 14:13:49 +0000406 std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
407 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
408 {
telsoa01c577f2c2018-08-31 09:22:23 +0100409 //Checks that the dimensionality of output is same as the split windows.
telsoa014fcda012018-03-09 14:13:49 +0000410 ViewOrigin const& e = m_ViewOrigins[w];
411 if (e.m_Origin.size() != outputDims)
412 {
413 throw InvalidArgumentException("MergerQueueDescriptor: Window origin have to "
414 "have the same dimensionality as the output tensor. "
415 "Window origin (index: " +
416 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
417 " dimensions, the output "
418 "tensor has " +
419 to_string(outputDims) + " dimensions.");
420 }
telsoa01c577f2c2018-08-31 09:22:23 +0100421 //Checks that the merge windows are within the output tensor.
telsoa014fcda012018-03-09 14:13:49 +0000422 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
423 {
424 if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
425 > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
426 {
427 throw InvalidArgumentException("MergerQueueDescriptor: Window extent coordinates have to "
428 "be smaller or equal than the size of the output in that coord.");
429 }
430 }
431 }
432}
433
434//---------------------------------------------------------------
435void FullyConnectedQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
436{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100437 ValidateNumInputs(workloadInfo, "FullyConnectedQueueDescriptor", 1);
438 ValidateNumOutputs(workloadInfo, "FullyConnectedQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000439 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "FullyConnectedQueueDescriptor", 2, "output");
440
441 if (!(workloadInfo.m_InputTensorInfos[0].GetNumDimensions() == 2 ||
442 workloadInfo.m_InputTensorInfos[0].GetNumDimensions() == 4))
443 {
444 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Input tensor must have 2 or 4 dimensions.");
445 }
446
447 if (m_Weight == nullptr)
448 {
449 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Weight tensor descriptor is missing.");
450 }
451
452 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "FullyConnectedQueueDescriptor", 2, "weight");
453
454 if (m_Parameters.m_BiasEnabled)
455 {
456 if (m_Bias == nullptr)
457 {
458 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Bias is enabled but "
459 "bias value tensor descriptor is missing.");
460 }
461
telsoa01c577f2c2018-08-31 09:22:23 +0100462 // Validates type and quantization values.
telsoa014fcda012018-03-09 14:13:49 +0000463 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
464 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "FullyConnectedQueueDescriptor");
465
466 ValidateTensorDataType(m_Bias->GetTensorInfo(),
467 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
468 "FullyConnectedQueueDescriptor", "bias");
469
470 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "FullyConnectedQueueDescriptor", 1, "bias");
471 }
472
473 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
474 workloadInfo.m_OutputTensorInfos[0], "FullyConnectedQueueDescriptor", "input", "weights", "output");
475}
476
477//---------------------------------------------------------------
478void NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
479{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100480 ValidateNumInputs(workloadInfo, "NormalizationQueueDescriptor", 1);
481 ValidateNumOutputs(workloadInfo, "NormalizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000482 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
483 workloadInfo.m_OutputTensorInfos[0],
484 "NormalizationQueueDescriptor",
485 "input",
486 "output");
487}
488
489void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
490{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100491 ValidateNumInputs(workloadInfo, "AdditionQueueDescriptor", 2);
492 ValidateNumOutputs(workloadInfo, "AdditionQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000493
494 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
495 workloadInfo.m_InputTensorInfos[1],
496 workloadInfo.m_OutputTensorInfos[0],
497 "AdditionQueueDescriptor",
498 "first input",
499 "second input");
500
501}
502
503//---------------------------------------------------------------
504void MultiplicationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
505{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100506 ValidateNumInputs(workloadInfo, "MultiplicationQueueDescriptor", 2);
507 ValidateNumOutputs(workloadInfo, "MultiplicationQueueDescriptor", 1);
surmeh01bceff2f2018-03-29 16:29:27 +0100508
509 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
510 workloadInfo.m_InputTensorInfos[1],
511 workloadInfo.m_OutputTensorInfos[0],
512 "MultiplicationQueueDescriptor",
513 "first input",
514 "second input");
telsoa014fcda012018-03-09 14:13:49 +0000515}
516
517void BatchNormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
518{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100519 ValidateNumInputs(workloadInfo, "BatchNormalizationQueueDescriptor", 1);
520 ValidateNumOutputs(workloadInfo, "BatchNormalizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000521 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
522 workloadInfo.m_OutputTensorInfos[0],
523 "BatchNormalizationQueueDescriptor",
524 "input",
525 "output");
526 ValidatePointer(m_Mean, "BatchNormalizationQueueDescriptor", "mean");
527 ValidatePointer(m_Variance, "BatchNormalizationQueueDescriptor", "variance");
528 ValidatePointer(m_Beta, "BatchNormalizationQueueDescriptor", "beta");
529 ValidatePointer(m_Gamma, "BatchNormalizationQueueDescriptor", "gamma");
530
531
532 ValidateTensorNumDimensions(m_Mean->GetTensorInfo(), "BatchNormalizationQueueDescriptor", 1, "mean");
533 ValidateTensorNumDimensions(m_Variance->GetTensorInfo(), "BatchNormalizationQueueDescriptor", 1, "variance");
534 ValidateTensorNumDimensions(m_Beta->GetTensorInfo(), "BatchNormalizationQueueDescriptor", 1, "beta");
535 ValidateTensorNumDimensions(m_Gamma->GetTensorInfo(), "BatchNormalizationQueueDescriptor", 1, "gamma");
536
537 ValidateTensorShapesMatch(
538 m_Mean->GetTensorInfo(), m_Variance->GetTensorInfo(), "BatchNormalizationQueueDescriptor", "mean", "variance");
539 ValidateTensorShapesMatch(
540 m_Mean->GetTensorInfo(), m_Beta->GetTensorInfo(), "BatchNormalizationQueueDescriptor", "mean", "beta");
541 ValidateTensorShapesMatch(
542 m_Mean->GetTensorInfo(), m_Gamma->GetTensorInfo(), "BatchNormalizationQueueDescriptor", "mean", "gamma");
543}
544
545void Convolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
546{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100547 ValidateNumInputs(workloadInfo, "Convolution2dQueueDescriptor", 1);
548 ValidateNumOutputs(workloadInfo, "Convolution2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000549
550 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "Convolution2dQueueDescriptor", 4, "input");
551 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "Convolution2dQueueDescriptor", 4, "output");
552
553 ValidatePointer(m_Weight, "Convolution2dQueueDescriptor", "weight");
554 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "Convolution2dQueueDescriptor", 4, "weight");
555 ValidateTensorDataType(m_Weight->GetTensorInfo(), workloadInfo.m_InputTensorInfos[0].GetDataType(),
556 "Convolution2dQueueDescriptor", "weight");
557 if (m_Parameters.m_BiasEnabled)
558 {
559 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "Convolution2dQueueDescriptor", 1, "bias");
560 ValidateTensorDataType(m_Bias->GetTensorInfo(),
561 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
562 "Convolution2dQueueDescriptor", "bias");
563 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
564 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "Convolution2dQueueDescriptor");
565 }
566
567 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
568 workloadInfo.m_OutputTensorInfos[0], "Convolution2dQueueDescriptor", "input", "weights", "output");
569}
570
571void DepthwiseConvolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
572{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100573 ValidateNumInputs(workloadInfo, "DepthwiseConvolution2dQueueDescriptor", 1);
574 ValidateNumOutputs(workloadInfo, "DepthwiseConvolution2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000575
576 ValidateTensorNumDimensions(
577 workloadInfo.m_InputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", 4, "input");
578 ValidateTensorNumDimensions(
579 workloadInfo.m_OutputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", 4, "output");
580
581 ValidatePointer(m_Weight, "DepthwiseConvolution2dQueueDescriptor", "weight");
582 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 4, "weight");
583
Nikhil Rajcec6b652018-10-12 13:51:57 +0100584 const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
585
Matteo Martincigh747ef822018-12-18 09:26:39 +0000586 // Expected weight shape: [ M, I, H, W ] - This shape does NOT depend on the data layout
587 // inputChannels * channelMultiplier should be equal to outputChannels.
telsoa014fcda012018-03-09 14:13:49 +0000588 const unsigned int numWeightChannelMultiplier = m_Weight->GetTensorInfo().GetShape()[0];
Matteo Martincigh747ef822018-12-18 09:26:39 +0000589 const unsigned int numWeightInputChannels = m_Weight->GetTensorInfo().GetShape()[1];
Nikhil Rajcec6b652018-10-12 13:51:57 +0100590 const unsigned int numWeightOutputChannels = workloadInfo.m_OutputTensorInfos[0].GetShape()[channelIndex];
telsoa014fcda012018-03-09 14:13:49 +0000591 if (numWeightChannelMultiplier * numWeightInputChannels != numWeightOutputChannels)
592 {
593 throw InvalidArgumentException(
594 boost::str(boost::format("DepthwiseConvolution2dQueueDescriptor: output_channels (provided %1%) should be "
595 "equal to input_channels (provided %2%) multiplied by channel_multiplier "
596 "(provided %3%).")
597 % numWeightOutputChannels % numWeightInputChannels % numWeightChannelMultiplier));
598 }
599
600 if (m_Parameters.m_BiasEnabled)
601 {
602 ValidatePointer(m_Bias, "DepthwiseConvolution2dQueueDescriptor", "bias");
603 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 1, "bias");
604 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
605 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor");
606
607 ValidateTensorDataType(m_Bias->GetTensorInfo(),
608 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
609 "DepthwiseConvolution2dQueueDescriptor", "bias");
610 }
611
612 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
613 workloadInfo.m_OutputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", "input", "weights", "output");
614}
615
616void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
617{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100618 ValidateNumInputs(workloadInfo, "PermuteQueueDescriptor", 1);
619 ValidateNumOutputs(workloadInfo, "PermuteQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000620
621 const PermutationVector& mapping = m_Parameters.m_DimMappings;
622
623 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
624 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
625
626 ValidateTensorNumDimensions(input, "PermuteQueueDescriptor", mapping.GetSize(), "input");
627 ValidateTensorNumDimensions(output, "PermuteQueueDescriptor", mapping.GetSize(), "output");
628
629 for (unsigned int i = 0; i < mapping.GetSize(); ++i)
630 {
631 if (input.GetShape()[i] != output.GetShape()[mapping[i]])
632 {
633 throw InvalidArgumentException("PermuteQueueDescriptor: src dimension " + to_string(i) +
634 " (=" + to_string(input.GetShape()[i]) + ") " +
635 "must match dst dimension " + to_string(mapping[i]) +
636 " (=" + to_string(output.GetShape()[mapping[i]]) + ")");
637 }
638 }
639}
640
641void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
642{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100643 ValidateNumInputs(workloadInfo, "Pooling2dQueueDescriptor", 1);
644 ValidateNumOutputs(workloadInfo, "Pooling2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000645
646 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "Pooling2dQueueDescriptor", 4, "input");
647 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "Pooling2dQueueDescriptor", 4, "output");
648}
649
650void ResizeBilinearQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
651{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100652 ValidateNumInputs(workloadInfo, "ResizeBilinearQueueDescriptor", 1);
653 ValidateNumOutputs(workloadInfo, "ResizeBilinearQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000654
655 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "ResizeBilinearQueueDescriptor", 4, "input");
656 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "ResizeBilinearQueueDescriptor", 4, "output");
657
telsoa01c577f2c2018-08-31 09:22:23 +0100658 // Resizes bilinear only changes width and height: batch and channel count must match.
telsoa014fcda012018-03-09 14:13:49 +0000659 {
660 const unsigned int inputBatchSize = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
661 const unsigned int outputBatchSize = workloadInfo.m_OutputTensorInfos[0].GetShape()[0];
662 if (inputBatchSize != outputBatchSize)
663 {
664 throw InvalidArgumentException(
665 boost::str(boost::format("ResizeBilinearQueueDescriptor: Input batch size (%1%) "
666 "does not match output batch size (%2%)") % inputBatchSize % outputBatchSize));
667 }
668 }
669
670 {
Matthew Bentham8800c002018-11-19 13:19:28 +0000671 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
James Conroy59540822018-10-11 12:39:05 +0100672 const unsigned int inputChannelCount =
Matthew Bentham8800c002018-11-19 13:19:28 +0000673 workloadInfo.m_InputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
James Conroy59540822018-10-11 12:39:05 +0100674 const unsigned int outputChannelCount =
Matthew Bentham8800c002018-11-19 13:19:28 +0000675 workloadInfo.m_OutputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
telsoa014fcda012018-03-09 14:13:49 +0000676 if (inputChannelCount != outputChannelCount)
677 {
678 throw InvalidArgumentException(
679 boost::str(boost::format("ResizeBilinearQueueDescriptor: Input channel count (%1%) "
680 "does not match output channel count (%2%)") % inputChannelCount % outputChannelCount));
681 }
682 }
683}
684
685void FakeQuantizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
686{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100687 ValidateNumInputs(workloadInfo, "FakeQuantizationQueueDescriptor", 1);
688 ValidateNumOutputs(workloadInfo, "FakeQuantizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000689
690 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "FakeQuantizationQueueDescriptor", 2, "input");
691 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "FakeQuantizationQueueDescriptor", 2, "output");
692 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
693 workloadInfo.m_OutputTensorInfos[0],
694 "FakeQuantizationQueueDescriptor",
695 "input",
696 "output");
697 if (m_Parameters.m_Min > m_Parameters.m_Max)
698 {
699 throw InvalidArgumentException("FakeQuantizationQueueDescriptor: min cannot be greater than max");
700 }
701
702}
703
704void L2NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
705{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100706 ValidateNumInputs(workloadInfo, "L2NormalizationQueueDescriptor", 1);
707 ValidateNumOutputs(workloadInfo, "L2NormalizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000708
709 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "L2NormalizationQueueDescriptor", 4, "input");
710 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "L2NormalizationQueueDescriptor", 4, "output");
711 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
712 workloadInfo.m_OutputTensorInfos[0],
713 "L2NormalizationQueueDescriptor",
714 "input",
715 "output");
716}
717
718void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
719{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100720 ValidateNumInputs(workloadInfo, "ConstantQueueDescriptor", 0);
721 ValidateNumOutputs(workloadInfo, "ConstantQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000722
723 if (!m_LayerOutput)
724 {
725 throw InvalidArgumentException("ConstantQueueDescriptor: No const input specified");
726 }
727
728 ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(),
729 workloadInfo.m_OutputTensorInfos[0],
730 "ConstantQueueDescriptor",
731 "constant",
732 "output");
733}
734
735void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
736{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100737 ValidateNumInputs(workloadInfo, "ReshapeQueueDescriptor", 1);
738 ValidateNumOutputs(workloadInfo, "ReshapeQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000739
740 if (workloadInfo.m_InputTensorInfos[0].GetNumElements() != workloadInfo.m_OutputTensorInfos[0].GetNumElements())
741 {
742 throw InvalidArgumentException("ReshapeQueueDescriptor: Input tensor has " +
743 to_string(workloadInfo.m_InputTensorInfos[0].GetNumElements()) + " but output tensor has " +
744 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
745 }
746}
747
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000748void SpaceToBatchNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
749{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100750 ValidateNumInputs(workloadInfo, "SpaceToBatchNdQueueDescriptor", 1);
751 ValidateNumOutputs(workloadInfo, "SpaceToBatchNdQueueDescriptor", 1);
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000752
753 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "SpaceToBatchNdQueueDescriptor", 4, "input");
754 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "SpaceToBatchNdQueueDescriptor", 4, "output");
755
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000756 if (m_Parameters.m_BlockShape.size() != 2)
757 {
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000758 throw InvalidArgumentException("Block Shape must contain 2 spatial dimensions");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000759 }
760
761 if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
762 {
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000763 throw InvalidArgumentException("Pad List must contain the same number of dimensions as Block Shape.");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000764 }
765
766 const TensorShape inputShape = workloadInfo.m_InputTensorInfos[0].GetShape();
767
768 std::pair<unsigned int, unsigned int> heightPad = m_Parameters.m_PadList[0];
769 std::pair<unsigned int, unsigned int> widthPad = m_Parameters.m_PadList[1];
770
Matthew Bentham8800c002018-11-19 13:19:28 +0000771 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
772 unsigned int inputHeight = inputShape[dimensionIndices.GetHeightIndex()]
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000773 + heightPad.first + heightPad.second;
774
Matthew Bentham8800c002018-11-19 13:19:28 +0000775 unsigned int inputWidth = inputShape[dimensionIndices.GetWidthIndex()]
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000776 + widthPad.first + widthPad.second;
777
778 unsigned int numInputElements = inputShape[0] * inputHeight * inputWidth
Matthew Bentham8800c002018-11-19 13:19:28 +0000779 * inputShape[dimensionIndices.GetChannelsIndex()];
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000780
781 if (workloadInfo.m_OutputTensorInfos[0].GetNumElements() != numInputElements)
782 {
783 throw InvalidArgumentException("SpaceToBatchNdQueueDescriptor: Input tensor has " +
784 to_string(numInputElements) + " after padding but output tensor has " +
785 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
786 }
787
788 if (inputHeight % m_Parameters.m_BlockShape[0] != 0 || inputWidth % m_Parameters.m_BlockShape[1] != 0)
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000789 {
790 throw InvalidArgumentException(
791 "Input shape after padding must be divisible by Block Shape in all spatial dimensions");
792 }
793}
794
telsoa014fcda012018-03-09 14:13:49 +0000795void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
796{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100797 ValidateNumInputs(workloadInfo, "FloorQueueDescriptor", 1);
798 ValidateNumOutputs(workloadInfo, "FlootQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000799
800 if (workloadInfo.m_InputTensorInfos[0] != workloadInfo.m_OutputTensorInfos[0])
801 {
802 throw InvalidArgumentException("FloorQueueDescriptor: Input and output tensor infos do not match.");
803 }
804}
805
telsoa01c577f2c2018-08-31 09:22:23 +0100806void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
807{
808 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "LstmQueueDescriptor", 2, "input");
809 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "LstmQueueDescriptor", 2, "output");
810}
811
812void ConvertFp32ToFp16QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
813{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100814 ValidateNumInputs(workloadInfo, "ConvertFp32ToFp16QueueDescriptor", 1);
815 ValidateNumOutputs(workloadInfo, "ConvertFp32ToFp16QueueDescriptor", 1);
telsoa01c577f2c2018-08-31 09:22:23 +0100816
817 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float32)
818 {
819 throw InvalidArgumentException("ConvertFp32ToFp16QueueDescriptor: Input tensor type must be Float32.");
820 }
821
822 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float16)
823 {
824 throw InvalidArgumentException("ConvertFp32ToFp16QueueDescriptor: Output tensor type must be Float16.");
825 }
826
827 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
828 workloadInfo.m_OutputTensorInfos[0],
829 "ConvertFp32ToFp16QueueDescriptor",
830 "input",
831 "output");
832}
833
834void ConvertFp16ToFp32QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
835{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100836 ValidateNumInputs(workloadInfo, "ConvertFp16ToFp32QueueDescriptor", 1);
837 ValidateNumOutputs(workloadInfo, "ConvertFp16ToFp32QueueDescriptor", 1);
telsoa01c577f2c2018-08-31 09:22:23 +0100838
839 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float16)
840 {
841 throw InvalidArgumentException("ConvertFp16ToFp32QueueDescriptor: Input tensor type must be Float16.");
842 }
843 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float32)
844 {
845 throw InvalidArgumentException("ConvertFp16ToFp32QueueDescriptor: Output tensor type must be Float32.");
846 }
847
848 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
849 workloadInfo.m_OutputTensorInfos[0],
850 "ConvertFp16ToFp32QueueDescriptor",
851 "input",
852 "output");
853}
854
Francis Murtaghe7a86a42018-08-29 12:42:10 +0100855void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
856{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100857 ValidateNumInputs(workloadInfo, "DivisionQueueDescriptor", 2);
858 ValidateNumOutputs(workloadInfo, "DivisionQueueDescriptor", 1);
Francis Murtaghe7a86a42018-08-29 12:42:10 +0100859
860 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
861 workloadInfo.m_InputTensorInfos[1],
862 workloadInfo.m_OutputTensorInfos[0],
863 "DivisionQueueDescriptor",
864 "first input",
865 "second input");
866}
867
David Beckc2044fe2018-09-05 15:00:38 +0100868void SubtractionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
869{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100870 ValidateNumInputs(workloadInfo, "SubtractionQueueDescriptor", 2);
871 ValidateNumOutputs(workloadInfo, "SubtractionQueueDescriptor", 1);
David Beckc2044fe2018-09-05 15:00:38 +0100872
873 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
874 workloadInfo.m_InputTensorInfos[1],
875 workloadInfo.m_OutputTensorInfos[0],
876 "SubtractionQueueDescriptor",
877 "first input",
878 "second input");
879}
880
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +0000881void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
882{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100883 ValidateNumInputs(workloadInfo, "MaximumQueueDescriptor", 2);
884 ValidateNumOutputs(workloadInfo, "MaximumQueueDescriptor", 1);
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +0000885
886 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
887 workloadInfo.m_InputTensorInfos[1],
888 workloadInfo.m_OutputTensorInfos[0],
889 "MaximumQueueDescriptor",
890 "first input",
891 "second input");
892}
893
narpra01a6bf9122018-09-10 09:50:09 +0100894void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
895{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100896 ValidateNumInputs(workloadInfo, "MeanQueueDescriptor", 1);
897 ValidateNumOutputs(workloadInfo, "MeanQueueDescriptor", 1);
narpra01eb061912018-09-10 17:35:27 +0100898
899 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
900 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
901
narpra0132b90462018-09-13 11:07:48 +0100902 if (m_Parameters.m_KeepDims)
narpra01eb061912018-09-10 17:35:27 +0100903 {
904 ValidateTensorNumDimensions(output, "MeanQueueDescriptor", input.GetNumDimensions(), "output");
905 }
narpra0132b90462018-09-13 11:07:48 +0100906 else if (m_Parameters.m_Axis.empty())
narpra01eb061912018-09-10 17:35:27 +0100907 {
908 ValidateTensorNumDimensions(output, "MeanQueueDescriptor", 1, "output");
909 }
910 else
911 {
narpra0132b90462018-09-13 11:07:48 +0100912 auto outputDim = input.GetNumDimensions() - boost::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
narpra01eb061912018-09-10 17:35:27 +0100913 ValidateTensorNumDimensions(output,
914 "MeanQueueDescriptor",
915 outputDim > 0 ? outputDim : 1,
916 "output");
917 }
narpra01a6bf9122018-09-10 09:50:09 +0100918}
919
jimfly012c9322a2018-09-19 10:59:49 +0100920void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
921{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100922 ValidateNumInputs(workloadInfo, "PadQueueDescriptor", 1);
923 ValidateNumOutputs(workloadInfo, "PadQueueDescriptor", 1);
jimfly012c9322a2018-09-19 10:59:49 +0100924
925 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
Nina Drozd661dfa72018-10-02 11:14:17 +0100926 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
927
jimfly012c9322a2018-09-19 10:59:49 +0100928 // input and output should have the same number of dimensions
929 ValidateTensorNumDimensions(output, "PadQueueDescriptor", input.GetNumDimensions(), "output");
930 // there should be entry in the pad list for each dimension in the input tensor
931 if (m_Parameters.m_PadList.size() != input.GetNumDimensions()) {
932 throw InvalidArgumentException("Pad List should contain the same number of entries as there"
933 " are dimensions in the input tensor that is " +
934 to_string(input.GetNumDimensions()) + " entries " +
935 " not " + to_string(m_Parameters.m_PadList.size()) + " entries.");
936 }
937}
938
Derek Lambertia9cca6a2019-03-25 15:41:58 +0000939void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
940{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100941 ValidateNumInputs(workloadInfo, "QuantizeQueueDescriptor", 1);
942 ValidateNumOutputs(workloadInfo, "QuantizeQueueDescriptor", 1);
Derek Lambertia9cca6a2019-03-25 15:41:58 +0000943
944
945 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float32)
946 {
947 throw InvalidArgumentException("Quantize only accepts Float32 inputs.");
948 }
949
950 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::QuantisedAsymm8 &&
951 workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::QuantisedSymm16)
952 {
953 throw InvalidArgumentException("Output of quantized layer must be quantized type.");
954 }
955}
956
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +0000957void BatchToSpaceNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
958{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100959 ValidateNumInputs(workloadInfo, "BatchToSpaceNdQueueDescriptor", 1);
960 ValidateNumOutputs(workloadInfo, "BatchToSpaceNdQueueDescriptor", 1);
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +0000961}
962
Conor Kennedy430b5d82018-11-14 15:28:28 +0000963void StridedSliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
964{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100965 ValidateNumInputs(workloadInfo, "StridedSliceQueueDescriptor", 1);
966 ValidateNumOutputs(workloadInfo, "StridedSliceQueueDescriptor", 1);
Conor Kennedy430b5d82018-11-14 15:28:28 +0000967
968 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
969 const uint32_t rank = input.GetNumDimensions();
970
Nattapat Chaimanowonga0d28442018-11-21 16:48:17 +0000971 if (rank > 4)
972 {
973 throw InvalidArgumentException(
974 "StridedSliceLayer: Input tensors with rank greater than 4 are not supported");
975 }
976
Conor Kennedy430b5d82018-11-14 15:28:28 +0000977 // Begin, End & Stride length must be of rank(input0)
978 if (m_Parameters.m_Begin.size() != rank)
979 {
980 throw InvalidArgumentException("StridedSliceLayer: Begin length must be of rank input0("
981 + to_string(rank) + ")");
982 }
983
984 if (m_Parameters.m_End.size() != rank)
985 {
986 throw InvalidArgumentException("StridedSliceLayer: End length must be of rank input0("
987 + to_string(rank) + ")");
988 }
989
990 if (m_Parameters.m_Stride.size() != rank)
991 {
992 throw InvalidArgumentException("StridedSliceLayer: Stride length must be of rank input0("
993 + to_string(rank) + ")");
994 }
995
996 // Stride entries must be non-zero
997 for (auto& stride : m_Parameters.m_Stride)
998 {
999 if (stride == 0)
1000 {
1001 throw InvalidArgumentException("StridedSliceLayer: Stride entries must be non-zero");
1002 }
1003 }
1004}
1005
kevmay0190539692018-11-29 08:40:19 +00001006void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1007{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001008 ValidateNumInputs(workloadInfo, "MinimumQueueDescriptor", 2);
1009 ValidateNumOutputs(workloadInfo, "MinimumQueueDescriptor", 1);
kevmay0190539692018-11-29 08:40:19 +00001010
1011 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1012 workloadInfo.m_InputTensorInfos[1],
1013 workloadInfo.m_OutputTensorInfos[0],
1014 "MinimumQueueDescriptor",
1015 "first input",
1016 "second input");
1017}
1018
Nattapat Chaimanowonga9a1cf12018-12-03 16:06:49 +00001019void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1020{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001021 ValidateNumInputs(workloadInfo, "DebugQueueDescriptor", 1);
1022 ValidateNumOutputs(workloadInfo, "DebugQueueDescriptor", 1);
Nattapat Chaimanowonga9a1cf12018-12-03 16:06:49 +00001023}
1024
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001025void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1026{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001027 ValidateNumInputs(workloadInfo, "EqualQueueDescriptor", 2);
1028 ValidateNumOutputs(workloadInfo, "EqualQueueDescriptor", 1);
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001029
1030 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1031 workloadInfo.m_InputTensorInfos[1],
1032 workloadInfo.m_OutputTensorInfos[0],
1033 "EqualQueueDescriptor",
1034 "first input",
1035 "second input");
kevmay012b4d88e2019-01-24 14:05:09 +00001036
1037 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
1038 {
1039 throw InvalidArgumentException("EqualQueueDescriptor: Output tensor type must be Boolean.");
1040 }
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001041}
1042
FrancisMurtagh878f0232018-12-19 10:56:15 +00001043void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1044{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001045 ValidateNumInputs(workloadInfo, "GreaterQueueDescriptor", 2);
1046 ValidateNumOutputs(workloadInfo, "GreaterQueueDescriptor", 1);
FrancisMurtagh878f0232018-12-19 10:56:15 +00001047
1048 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1049 workloadInfo.m_InputTensorInfos[1],
1050 workloadInfo.m_OutputTensorInfos[0],
1051 "GreaterQueueDescriptor",
1052 "first input",
1053 "second input");
kevmay012b4d88e2019-01-24 14:05:09 +00001054
1055 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
1056 {
1057 throw InvalidArgumentException("GreaterQueueDescriptor: Output tensor type must be Boolean.");
1058 }
FrancisMurtagh878f0232018-12-19 10:56:15 +00001059}
1060
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001061void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1062{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001063 ValidateNumInputs(workloadInfo, "RsqrtQueueDescriptor", 1);
1064 ValidateNumOutputs(workloadInfo, "RsqrtQueueDescriptor", 1);
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001065 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1066 workloadInfo.m_OutputTensorInfos[0],
1067 "RsqrtQueueDescriptor",
1068 "input",
1069 "output");
1070}
1071
narpra01b89b05f2019-01-16 09:53:09 +00001072void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1073{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001074 ValidateNumInputs(workloadInfo, "GatherQueueDescriptor", 2);
1075 ValidateNumOutputs(workloadInfo, "GatherQueueDescriptor", 1);
narpra014951d842019-01-18 16:53:53 +00001076
1077 const TensorInfo& indices = workloadInfo.m_InputTensorInfos[1];
1078
1079 if (indices.GetDataType() != DataType::Signed32)
1080 {
1081 throw InvalidArgumentException("GatherQueueDescriptor: Indices tensor type must be int32.");
1082 }
1083
1084 const TensorInfo& params = workloadInfo.m_InputTensorInfos[0];
1085 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1086 unsigned int paramsDim = params.GetNumDimensions();
1087 unsigned int indicesDim = indices.GetNumDimensions();
1088 unsigned int outputDim = paramsDim - 1 + indicesDim;
1089
1090 ValidateTensorNumDimensions(output, "GatherQueueDescriptor", outputDim, "output");
narpra01b89b05f2019-01-16 09:53:09 +00001091}
1092
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001093void DetectionPostProcessQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1094{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001095 ValidateNumInputs(workloadInfo, "DetectionPostProcessQueueDescriptor", 2);
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001096
1097 if (workloadInfo.m_OutputTensorInfos.size() != 4)
1098 {
1099 throw InvalidArgumentException("DetectionPostProcessQueueDescriptor: Requires exactly four outputs. " +
1100 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
1101 }
1102
1103 if (m_Anchors == nullptr)
1104 {
1105 throw InvalidArgumentException("DetectionPostProcessQueueDescriptor: Anchors tensor descriptor is missing.");
1106 }
1107
1108 const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
1109 const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
1110 const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
1111 const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
Narumol Prangnawarat6d302bf2019-02-04 11:46:26 +00001112 const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
1113 const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001114 const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
1115
1116 ValidateTensorNumDimensions(boxEncodingsInfo, "DetectionPostProcessQueueDescriptor", 3, "box encodings");
1117 ValidateTensorNumDimensions(scoresInfo, "DetectionPostProcessQueueDescriptor", 3, "scores");
1118 ValidateTensorNumDimensions(anchorsInfo, "DetectionPostProcessQueueDescriptor", 2, "anchors");
1119
1120 ValidateTensorNumDimensions(detectionBoxesInfo, "DetectionPostProcessQueueDescriptor", 3, "detection boxes");
1121 ValidateTensorNumDimensions(detectionScoresInfo, "DetectionPostProcessQueueDescriptor", 2, "detection scores");
1122 ValidateTensorNumDimensions(detectionClassesInfo, "DetectionPostProcessQueueDescriptor", 2, "detection classes");
1123 ValidateTensorNumDimensions(numDetectionsInfo, "DetectionPostProcessQueueDescriptor", 1, "num detections");
1124
1125 ValidateTensorDataType(detectionBoxesInfo, DataType::Float32,
1126 "DetectionPostProcessQueueDescriptor", "detection boxes");
1127 ValidateTensorDataType(detectionScoresInfo, DataType::Float32,
1128 "DetectionPostProcessQueueDescriptor", "detection scores");
1129 ValidateTensorDataType(detectionClassesInfo, DataType::Float32,
1130 "DetectionPostProcessQueueDescriptor", "detection classes");
1131 ValidateTensorDataType(numDetectionsInfo, DataType::Float32,
1132 "DetectionPostProcessQueueDescriptor", "num detections");
1133
1134 if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f)
1135 {
1136 throw InvalidArgumentException("DetectionPostProcessQueueDescriptor: Intersection over union threshold "
1137 "must be positive and less than or equal to 1.");
1138 }
1139 if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
1140 {
1141 throw InvalidArgumentException("DetectionPostProcessQueueDescriptor: Number of classes with background "
1142 "should be equal to number of classes + 1.");
1143 }
1144}
1145
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00001146void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1147{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001148 ValidateNumInputs(workloadInfo, "DequantizeQueueDescriptor", 1);
1149 ValidateNumOutputs(workloadInfo, "DequantizeQueueDescriptor", 1);
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00001150
1151 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::QuantisedAsymm8 &&
1152 workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::QuantisedSymm16)
1153 {
1154 throw InvalidArgumentException("Input to dequantize layer must be quantized type.");
1155 }
1156
1157 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float32)
1158 {
1159 throw InvalidArgumentException("Output of dequantize layer must be Float32 type.");
1160 }
1161}
1162
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001163void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1164{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001165 ValidateNumInputs(workloadInfo, "MergeQueueDescriptor", 2);
1166 ValidateNumOutputs(workloadInfo, "MergeQueueDescriptor", 1);
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001167
1168 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1169 workloadInfo.m_InputTensorInfos[1],
1170 "MergeQueueDescriptor",
1171 "input0",
1172 "input1");
1173
1174 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1175 workloadInfo.m_OutputTensorInfos[0],
1176 "MergeQueueDescriptor",
1177 "input0",
1178 "output");
1179
1180 const DataType dataType = workloadInfo.m_InputTensorInfos[0].GetDataType();
1181 ValidateTensorDataType(workloadInfo.m_InputTensorInfos[1], dataType, "MergeQueueDescriptor", "input1");
1182 ValidateTensorDataType(workloadInfo.m_OutputTensorInfos[0], dataType, "MergeQueueDescriptor", "output");
1183}
1184
Sadik Armaganeff363d2019-04-05 15:25:46 +01001185void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1186{
1187 ValidateNumInputs(workloadInfo, "SwitchQueueDescriptor", 2);
1188 ValidateNumOutputs(workloadInfo, "SwitchQueueDescriptor", 2);
1189
1190 std::vector<DataType> supportedTypes = {
1191 DataType::Float32,
1192 DataType::QuantisedAsymm8,
1193 DataType::QuantisedSymm16
1194 };
1195
1196 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1197 supportedTypes,
1198 "SwitchQueueDescriptor");
1199
1200 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1201 supportedTypes,
1202 "SwitchQueueDescriptor");
1203
1204 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1205 supportedTypes,
1206 "SwitchQueueDescriptor");
1207
1208 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1209 workloadInfo.m_OutputTensorInfos[0],
1210 "SwitchQueueDescriptor",
1211 "input0",
1212 "output0");
1213
1214 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1215 workloadInfo.m_OutputTensorInfos[1],
1216 "SwitchQueueDescriptor",
1217 "input0",
1218 "output1");
1219}
1220
Matteo Martincigh49124022019-01-11 13:25:59 +00001221void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1222{
1223 // This is internally generated so it should not need validation.
1224}
1225
Nattapat Chaimanowonga0d28442018-11-21 16:48:17 +00001226} //namespace armnn