blob: a1d00c69458aca465e5b09ed9b6b7968eef816e1 [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>
Aron Virginas-Tard4f0fea2019-04-09 14:08:06 +010017#include <boost/numeric/conversion/cast.hpp>
telsoa014fcda012018-03-09 14:13:49 +000018
Matteo Martincigh21350152018-11-28 16:22:22 +000019using namespace armnnUtils;
20
telsoa014fcda012018-03-09 14:13:49 +000021namespace armnn
22{
23
24//---------------------------------------------------------------
25DataType GetBiasDataType(DataType inputDataType)
26{
27 switch (inputDataType)
28 {
telsoa01c577f2c2018-08-31 09:22:23 +010029 case DataType::Float16:
30 return DataType::Float16;
telsoa014fcda012018-03-09 14:13:49 +000031 case DataType::Float32:
32 return DataType::Float32;
33 case DataType::QuantisedAsymm8:
34 return DataType::Signed32;
Ruomei Yan88d44b82019-05-23 14:29:06 +010035 case DataType::QuantisedSymm16:
36 return DataType::Signed32;
telsoa014fcda012018-03-09 14:13:49 +000037 default:
38 BOOST_ASSERT_MSG(false, "Invalid input data type");
39 return DataType::Float32;
40 }
41}
42
43namespace
44{
45
46//---------------------------------------------------------------
47//android ndk does not support std::to_string function.
48template <typename T>
49std::string to_string(T value)
50{
51 std::ostringstream os;
52 os << value;
53 return os.str();
54}
55
56//---------------------------------------------------------------
57void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName)
58{
59 if (!ptr)
60 {
61 throw InvalidArgumentException(descName + ": Invalid null pointer. The " +
62 paramName + " parameter must be set.");
63 }
64}
65
66//---------------------------------------------------------------
67void ValidateTensorShapesMatch(const TensorInfo& first,
68 const TensorInfo& second,
69 std::string const& descName,
70 std::string const& firstName,
71 std::string const& secondName)
72{
73 if (first.GetShape() != second.GetShape())
74 {
75 throw InvalidArgumentException(descName + ": "
76 + firstName + " & " + secondName + " must have identical shapes");
77 }
78}
79
80//---------------------------------------------------------------
Sadik Armaganeff363d2019-04-05 15:25:46 +010081void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000082{
Sadik Armaganeff363d2019-04-05 15:25:46 +010083 if (workloadInfo.m_InputTensorInfos.size() != expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000084 {
85 throw InvalidArgumentException(descName +
Sadik Armaganeff363d2019-04-05 15:25:46 +010086 ": Requires exactly " + to_string(expectedSize) + "input(s). " +
telsoa014fcda012018-03-09 14:13:49 +000087 to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided.");
88 }
89}
90
91//---------------------------------------------------------------
Sadik Armaganeff363d2019-04-05 15:25:46 +010092void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000093{
Sadik Armaganeff363d2019-04-05 15:25:46 +010094 if (workloadInfo.m_OutputTensorInfos.size() != expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000095 {
96 throw InvalidArgumentException(descName +
Sadik Armaganeff363d2019-04-05 15:25:46 +010097 ": Requires exactly " + to_string(expectedSize) + " output(s). " +
telsoa014fcda012018-03-09 14:13:49 +000098 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
99 }
100}
101
102//---------------------------------------------------------------
103void ValidateTensorNumDimensions(const TensorInfo& tensor,
104 std::string const& descName,
105 unsigned int numDimensions,
106 std::string const& tensorName)
107{
108 if (tensor.GetNumDimensions() != numDimensions)
109 {
110 throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " +
111 to_string(tensor.GetNumDimensions()) + " dimensions for " +
112 tensorName + " tensor.");
113 }
114}
115
116//---------------------------------------------------------------
117void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
118 const std::string& descName, std::string const& tensorName)
119{
120 if (tensor.GetDataType() != dataType)
121 {
122 throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
123 GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
124 }
125}
126
127//---------------------------------------------------------------
Matteo Martincighe851b3d2019-05-28 14:31:20 +0100128void ValidateTensorQuantizationSpace(const TensorInfo& first,
129 const TensorInfo& second,
130 const std::string& descName,
131 std::string const& firstName,
132 std::string const& secondName)
133{
134 if (!first.IsQuantized() ||
135 !second.IsQuantized())
136 {
137 // Not a quantized type, ignore the validation
138 return;
139 }
140
141 DataType firstDataType = first.GetDataType();
142 DataType secondDataType = second.GetDataType();
143
144 if (firstDataType != secondDataType)
145 {
146 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
147 " must be of the same quantized type, " +
148 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
149 secondName + " is " + GetDataTypeName(secondDataType));
150 }
151
152 if (!first.IsTypeSpaceMatch(second))
153 {
154 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
155 " must have the same quantization space, " +
156 firstName + " has offset " + to_string(first.GetQuantizationOffset()) +
157 " and scale " + to_string(first.GetQuantizationScale()) + ", " +
158 secondName + " has offset " + to_string(second.GetQuantizationOffset()) +
159 " and scale " + to_string(second.GetQuantizationScale()));
160 }
161}
162
163//---------------------------------------------------------------
telsoa014fcda012018-03-09 14:13:49 +0000164void ValidateBiasTensorQuantization(const TensorInfo& biasTensor, const TensorInfo& inputTensorInfo,
165 const TensorInfo& weightsTensorInfo, const std::string& descName)
166{
167 if (biasTensor.GetQuantizationOffset() != 0)
168 {
169 throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
170 to_string(biasTensor.GetQuantizationOffset()));
171 }
172 const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightsTensorInfo.GetQuantizationScale();
kevmay016c46dd32018-12-17 15:32:45 +0000173 if (std::abs(biasTensor.GetQuantizationScale() - expectedScale) > 0.00000001f)
telsoa014fcda012018-03-09 14:13:49 +0000174 {
175 // Print the float values with extra precision to see very small differences
176 std::stringstream msg;
177 msg << std::setprecision(10) << descName << ": Expected " << expectedScale <<
178 " quantization scale for bias tensor (the product of the input and weight scales), but got " <<
179 biasTensor.GetQuantizationScale();
180 throw InvalidArgumentException(msg.str());
181 }
182}
183
184//---------------------------------------------------------------
185void ValidateTensors(const std::vector<ITensorHandle*>& vec,
186 unsigned int numExpected,
187 const std::string& descName,
188 const std::string& varName)
189{
190 if (vec.empty() && numExpected > 0)
191 {
192 throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
193 }
194
195 for (unsigned int i = 0; i < numExpected; ++i)
196 {
197 if (!vec[i])
198 {
199 throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
200 }
201 }
202}
203
204//---------------------------------------------------------------
205void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
206 const TensorInfo& second,
207 const TensorInfo& output,
208 std::string const& descName,
209 std::string const& firstName,
210 std::string const& secondName)
211{
212 // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
213 // broadcasted.
214 if (first.GetNumDimensions() != second.GetNumDimensions())
215 {
216 throw InvalidArgumentException(descName + ": Tensors "
217 + firstName + " & " + secondName
218 + " must have the same number of dimensions in order to be broadcasted");
219 }
220 uint32_t numDims = first.GetNumDimensions();
221 std::vector<uint32_t> outputDims(numDims, 0u);
222 for (uint32_t i = 0; i < numDims; i++)
223 {
224 const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i];
225 const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1);
226 if (dimsNotEqual && dimsNotOne)
227 {
228 throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes");
229 }
230 outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]);
231 }
232 TensorShape broadcastShape = TensorShape(boost::numeric_cast<unsigned int>(outputDims.size()), outputDims.data());
233 if (broadcastShape != output.GetShape())
234 {
235 throw InvalidArgumentException(descName + ": The tensor shape resulting from adding "
236 + firstName + " & " + secondName
237 + " does not match the output shape");
238 }
239}
240
241//---------------------------------------------------------------
242/// Validates that the output tensor's quantization scale is greater than the product
243/// of the two input tensors' quantization scales. This is a requirement of the implementation of
244/// the quantized multiplication.
245void ValidateTensorQuantizationMultiplier(const TensorInfo& inputTensor1, const TensorInfo& inputTensor2,
246 const TensorInfo& outputTensorInfo, std::string const& descName,
247 const std::string& inputTensor1Name, const std::string& inputTensor2Name, const std::string& outputTensorName)
248{
249 if (outputTensorInfo.GetDataType() == DataType::QuantisedAsymm8)
250 {
251 if (outputTensorInfo.GetQuantizationScale() <=
252 inputTensor1.GetQuantizationScale() * inputTensor2.GetQuantizationScale())
253 {
254 std::stringstream msg;
255 msg << descName << ": Quantization scale of " << outputTensorName << " is not greater than " <<
256 "the product of the " << inputTensor1Name << " and " << inputTensor2Name << " tensors";
257 throw InvalidArgumentException(msg.str());
258 }
259 }
260}
261
Sadik Armaganeff363d2019-04-05 15:25:46 +0100262//---------------------------------------------------------------
263void ValidateDataTypes(const TensorInfo& info,
264 const std::vector<armnn::DataType>& supportedTypes,
265 std::string const& descName)
266{
267 auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
268 if (iterator == supportedTypes.end())
269 {
270 throw InvalidArgumentException(descName + ": " + " Tensor type is not supported.");
271 }
272}
273
telsoa014fcda012018-03-09 14:13:49 +0000274} //namespace
275
276void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
277 unsigned int numExpectedIn, unsigned int numExpectedOut) const
278{
279 ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
280 ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
281}
282
283//---------------------------------------------------------------
284void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
285{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100286 ValidateNumInputs(workloadInfo, "MemCopyQueueDescriptor", 1);
287 ValidateNumOutputs(workloadInfo, "MemCopyQueueDescriptor" , 1);
telsoa014fcda012018-03-09 14:13:49 +0000288
289 if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
290 {
291 throw InvalidArgumentException(boost::str(
292 boost::format("Number of input infos (%1%) does not match the number of output infos (%2%)")
293 % workloadInfo.m_InputTensorInfos.size() % workloadInfo.m_OutputTensorInfos.size()));
294 }
295
296 for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
297 {
298 if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
299 workloadInfo.m_OutputTensorInfos[i].GetNumElements())
300 {
301 throw InvalidArgumentException(boost::str(
302 boost::format("Number of elements for tensor input and output %1% does not match")
303 % i ));
304 }
305 }
306
307 if (m_Inputs.size() != m_Outputs.size())
308 {
309 throw InvalidArgumentException(boost::str(
310 boost::format("Number of inputs (%1%) does not match the number of outputs (%2%)")
311 % m_Inputs.size() % m_Outputs.size()));
312 }
313
314 for (unsigned int i = 0; i < m_Inputs.size(); ++i)
315 {
316 if (!m_Inputs[i])
317 {
318 throw InvalidArgumentException(boost::str(boost::format("Invalid null input %1%") % i));
319 }
320
321 if (!m_Outputs[i])
322 {
323 throw InvalidArgumentException(boost::str(boost::format("Invalid null output %1%") % i));
324 }
325 }
326}
327
328//---------------------------------------------------------------
329void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
330{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100331 ValidateNumInputs(workloadInfo, "ActivationQueueDescriptor", 1);
332 ValidateNumOutputs(workloadInfo, "ActivationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000333 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
334 workloadInfo.m_OutputTensorInfos[0],
335 "ActivationQueueDescriptor",
336 "input",
337 "output");
Nattapat Chaimanowongae2c5f02019-04-24 16:19:57 +0100338
339 std::vector<DataType> supportedTypes = {
340 DataType::Float32,
341 DataType::Float16,
Teresa Charlin18515e22019-04-24 10:17:46 +0100342 DataType::QuantisedAsymm8,
343 DataType::QuantisedSymm16
Nattapat Chaimanowongae2c5f02019-04-24 16:19:57 +0100344 };
345
346 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
347 supportedTypes,
348 "ActivationQueueDescriptor");
349
350 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
351 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
352 "ActivationQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000353}
354
355//---------------------------------------------------------------
356void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
357{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100358 ValidateNumInputs(workloadInfo, "SoftmaxQueueDescriptor", 1);
359 ValidateNumOutputs(workloadInfo, "SoftmaxQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000360
361 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
362 workloadInfo.m_OutputTensorInfos[0],
363 "SoftmaxQueueDescriptor",
364 "input",
365 "output");
nikraj01248683f2019-05-29 16:46:50 +0100366
367 std::vector<DataType> supportedTypes =
368 {
369 DataType::Float16,
370 DataType::Float32,
371 DataType::QuantisedAsymm8,
372 DataType::QuantisedSymm16
373 };
374
375 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
376 supportedTypes,
377 "SoftmaxQueueDescriptor");
378
379 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
380 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
381 "SoftmaxQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000382}
383
384//---------------------------------------------------------------
385void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
386{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100387 ValidateNumInputs(workloadInfo, "SplitterQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000388
Ruomei Yan25339c32019-05-28 16:48:20 +0100389 // Check the supported data types
390 std::vector<DataType> supportedTypes =
391 {
392 DataType::Float32,
393 DataType::Float16,
394 DataType::Boolean,
395 DataType::Signed32,
396 DataType::QuantisedAsymm8,
397 DataType::QuantisedSymm16
398 };
399
400 for (unsigned long i = 0; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
401 {
402 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[i],
403 supportedTypes,
404 "SplitterQueueDescriptor");
405 }
406 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
407 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
408 "SplitterQueueDescriptor");
409
telsoa014fcda012018-03-09 14:13:49 +0000410 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
411 {
412 throw InvalidArgumentException("SplitterQueueDescriptor: At least one output needs to be provided.");
413 }
414
415 if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
416 {
417 throw InvalidArgumentException(
418 "SplitterQueueDescriptor: Number of split windows "
419 "has to match number of workloadInfo.m_OutputTensorInfos. "
420 "Number of windows: " +
421 to_string(m_ViewOrigins.size()) +
422 ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
423 }
424
telsoa01c577f2c2018-08-31 09:22:23 +0100425 //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
telsoa014fcda012018-03-09 14:13:49 +0000426 std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
427 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
428 {
telsoa01c577f2c2018-08-31 09:22:23 +0100429 //Checks that the dimensionality of input is same as the split windows.
telsoa014fcda012018-03-09 14:13:49 +0000430 ViewOrigin const& e = m_ViewOrigins[w];
431 if (e.m_Origin.size() != inputDims)
432 {
433 throw InvalidArgumentException("SplitterQueueDescriptor: Window origin have to "
434 "have the same dimensionality as the input tensor. "
435 "Window origin (index: " +
436 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
437 " dimensions, the input "
438 "tensor has " +
439 to_string(inputDims) + " dimensions.");
440 }
441 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
442 {
443 if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
444 workloadInfo.m_InputTensorInfos[0].GetShape()[i])
445 {
446 throw InvalidArgumentException("SplitterQueueDescriptor: Window extent coordinates have to "
447 "be smaller or equal than the size of the input in that coord.");
448 }
449 }
450 }
451}
452
453//---------------------------------------------------------------
Jim Flynne242f2d2019-05-22 14:24:13 +0100454void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
telsoa014fcda012018-03-09 14:13:49 +0000455{
Jim Flynne242f2d2019-05-22 14:24:13 +0100456 ValidateNumOutputs(workloadInfo, "ConcatQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000457
458 if (m_Inputs.size() <= 0)
459 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100460 throw InvalidArgumentException("ConcatQueueDescriptor: At least one input needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000461 }
462 if (m_Outputs.size() <= 0)
463 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100464 throw InvalidArgumentException("ConcatQueueDescriptor: At least one output needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000465 }
466
467 if (workloadInfo.m_InputTensorInfos.size() <= 0)
468 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100469 throw InvalidArgumentException("ConcatQueueDescriptor: At least one TensorInfo input needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000470 }
471 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
472 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100473 throw InvalidArgumentException("ConcatQueueDescriptor: At least one TensorInfo output needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000474 }
475
Nikhil Raj8599a412018-11-19 14:51:07 +0000476 if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
477 {
478 throw InvalidArgumentException("Invalid Concatenation Axis provided");
479 }
480
481 if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
482 {
483 return;
484 }
485
telsoa014fcda012018-03-09 14:13:49 +0000486 if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
487 {
488 throw InvalidArgumentException(
Jim Flynne242f2d2019-05-22 14:24:13 +0100489 "ConcatQueueDescriptor: Number of split windows "
telsoa014fcda012018-03-09 14:13:49 +0000490 "has to match number of workloadInfo.m_InputTensorInfos. "
491 "Number of windows: " +
492 to_string(m_ViewOrigins.size()) +
493 ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
494 }
495
telsoa01c577f2c2018-08-31 09:22:23 +0100496 //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
telsoa014fcda012018-03-09 14:13:49 +0000497 std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
498 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
499 {
telsoa01c577f2c2018-08-31 09:22:23 +0100500 //Checks that the dimensionality of output is same as the split windows.
telsoa014fcda012018-03-09 14:13:49 +0000501 ViewOrigin const& e = m_ViewOrigins[w];
502 if (e.m_Origin.size() != outputDims)
503 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100504 throw InvalidArgumentException("ConcatQueueDescriptor: Window origin have to "
telsoa014fcda012018-03-09 14:13:49 +0000505 "have the same dimensionality as the output tensor. "
506 "Window origin (index: " +
507 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
508 " dimensions, the output "
509 "tensor has " +
510 to_string(outputDims) + " dimensions.");
511 }
telsoa01c577f2c2018-08-31 09:22:23 +0100512 //Checks that the merge windows are within the output tensor.
telsoa014fcda012018-03-09 14:13:49 +0000513 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
514 {
515 if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
516 > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
517 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100518 throw InvalidArgumentException("ConcatQueueDescriptor: Window extent coordinates have to "
telsoa014fcda012018-03-09 14:13:49 +0000519 "be smaller or equal than the size of the output in that coord.");
520 }
521 }
522 }
Jim Flynncbb66aa2019-05-15 13:03:54 +0100523
524 // Check the supported data types
525 std::vector<DataType> supportedTypes =
526 {
527 DataType::Float32,
528 DataType::Float16,
529 DataType::Boolean,
530 DataType::Signed32,
531 DataType::QuantisedAsymm8,
532 DataType::QuantisedSymm16
533 };
534
535 for (unsigned long i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
536 {
537 ValidateDataTypes(workloadInfo.m_InputTensorInfos[i],
538 supportedTypes,
Jim Flynne242f2d2019-05-22 14:24:13 +0100539 "ConcatQueueDescriptor");
Jim Flynncbb66aa2019-05-15 13:03:54 +0100540 }
541 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
542 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
Jim Flynne242f2d2019-05-22 14:24:13 +0100543 "ConcatQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000544}
545
546//---------------------------------------------------------------
547void FullyConnectedQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
548{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100549 ValidateNumInputs(workloadInfo, "FullyConnectedQueueDescriptor", 1);
550 ValidateNumOutputs(workloadInfo, "FullyConnectedQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000551 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "FullyConnectedQueueDescriptor", 2, "output");
552
553 if (!(workloadInfo.m_InputTensorInfos[0].GetNumDimensions() == 2 ||
554 workloadInfo.m_InputTensorInfos[0].GetNumDimensions() == 4))
555 {
556 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Input tensor must have 2 or 4 dimensions.");
557 }
558
559 if (m_Weight == nullptr)
560 {
561 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Weight tensor descriptor is missing.");
562 }
563
564 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "FullyConnectedQueueDescriptor", 2, "weight");
565
566 if (m_Parameters.m_BiasEnabled)
567 {
568 if (m_Bias == nullptr)
569 {
570 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Bias is enabled but "
571 "bias value tensor descriptor is missing.");
572 }
573
telsoa01c577f2c2018-08-31 09:22:23 +0100574 // Validates type and quantization values.
telsoa014fcda012018-03-09 14:13:49 +0000575 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
576 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "FullyConnectedQueueDescriptor");
577
578 ValidateTensorDataType(m_Bias->GetTensorInfo(),
579 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
580 "FullyConnectedQueueDescriptor", "bias");
581
582 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "FullyConnectedQueueDescriptor", 1, "bias");
583 }
584
585 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
586 workloadInfo.m_OutputTensorInfos[0], "FullyConnectedQueueDescriptor", "input", "weights", "output");
Francis Murtagh46c09d02019-05-28 08:15:28 +0100587
588 // Check the supported data types
589 std::vector<DataType> supportedTypes =
590 {
591 DataType::Float32,
592 DataType::Float16,
593 DataType::QuantisedAsymm8,
594 DataType::QuantisedSymm16
595 };
596
597 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
598 supportedTypes,
599 "FullyConnectedQueueDescriptor");
600
601 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
602 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
603 "FullyConnectedQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000604}
605
606//---------------------------------------------------------------
607void NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
608{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100609 ValidateNumInputs(workloadInfo, "NormalizationQueueDescriptor", 1);
610 ValidateNumOutputs(workloadInfo, "NormalizationQueueDescriptor", 1);
Matteo Martincigh2fc70c52019-06-05 14:12:48 +0100611
612 // Check the supported data types
613 std::vector<DataType> supportedTypes =
614 {
615 DataType::Float16,
616 DataType::Float32,
Matteo Martincigh6aeb7712019-06-05 17:23:29 +0100617 DataType::QuantisedAsymm8,
618 DataType::QuantisedSymm16
Matteo Martincigh2fc70c52019-06-05 14:12:48 +0100619 };
620
621 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
622 supportedTypes,
623 "NormalizationQueueDescriptor");
624
625 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
626 { workloadInfo.m_InputTensorInfos[0].GetDataType() },
627 "NormalizationQueueDescriptor");
628
telsoa014fcda012018-03-09 14:13:49 +0000629 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
630 workloadInfo.m_OutputTensorInfos[0],
631 "NormalizationQueueDescriptor",
632 "input",
633 "output");
634}
635
636void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
637{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100638 ValidateNumInputs(workloadInfo, "AdditionQueueDescriptor", 2);
639 ValidateNumOutputs(workloadInfo, "AdditionQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000640
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100641 std::vector<DataType> supportedTypes = {
642 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +0100643 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +0100644 DataType::QuantisedSymm16,
645 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100646 };
647
648 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
649 supportedTypes,
650 "AdditionQueueDescriptor");
651
652 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
653 supportedTypes,
654 "AdditionQueueDescriptor");
655
656 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
657 supportedTypes,
658 "AdditionQueueDescriptor");
659
telsoa014fcda012018-03-09 14:13:49 +0000660 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
661 workloadInfo.m_InputTensorInfos[1],
662 workloadInfo.m_OutputTensorInfos[0],
663 "AdditionQueueDescriptor",
664 "first input",
665 "second input");
telsoa014fcda012018-03-09 14:13:49 +0000666}
667
668//---------------------------------------------------------------
669void MultiplicationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
670{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100671 ValidateNumInputs(workloadInfo, "MultiplicationQueueDescriptor", 2);
672 ValidateNumOutputs(workloadInfo, "MultiplicationQueueDescriptor", 1);
surmeh01bceff2f2018-03-29 16:29:27 +0100673
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100674 std::vector<DataType> supportedTypes = {
675 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +0100676 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +0100677 DataType::QuantisedSymm16,
678 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100679 };
680
681 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
682 supportedTypes,
683 "MultiplicationQueueDescriptor");
684
685 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
686 supportedTypes,
687 "MultiplicationQueueDescriptor");
688
689 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
690 supportedTypes,
691 "MultiplicationQueueDescriptor");
692
surmeh01bceff2f2018-03-29 16:29:27 +0100693 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
694 workloadInfo.m_InputTensorInfos[1],
695 workloadInfo.m_OutputTensorInfos[0],
696 "MultiplicationQueueDescriptor",
697 "first input",
698 "second input");
telsoa014fcda012018-03-09 14:13:49 +0000699}
700
701void BatchNormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
702{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100703 ValidateNumInputs(workloadInfo, "BatchNormalizationQueueDescriptor", 1);
704 ValidateNumOutputs(workloadInfo, "BatchNormalizationQueueDescriptor", 1);
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100705
706 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
707 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
708
709 std::vector<DataType> supportedTypes =
710 {
711 DataType::Float16,
712 DataType::Float32,
Matteo Martincighf5507132019-06-04 10:59:47 +0100713 DataType::QuantisedAsymm8,
714 DataType::QuantisedSymm16
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100715 };
716
717 ValidateDataTypes(input, supportedTypes, "BatchNormalizationQueueDescriptor");
718 ValidateDataTypes(output, supportedTypes, "BatchNormalizationQueueDescriptor");
719
720 ValidateDataTypes(output, { input.GetDataType() }, "BatchNormalizationQueueDescriptor");
721
722 ValidateTensorQuantizationSpace(input, output, "BatchNormalizationQueueDescriptor", "input", "output");
723
telsoa014fcda012018-03-09 14:13:49 +0000724 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
725 workloadInfo.m_OutputTensorInfos[0],
726 "BatchNormalizationQueueDescriptor",
727 "input",
728 "output");
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100729
730 ValidatePointer(m_Mean, "BatchNormalizationQueueDescriptor", "mean");
telsoa014fcda012018-03-09 14:13:49 +0000731 ValidatePointer(m_Variance, "BatchNormalizationQueueDescriptor", "variance");
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100732 ValidatePointer(m_Beta, "BatchNormalizationQueueDescriptor", "beta");
733 ValidatePointer(m_Gamma, "BatchNormalizationQueueDescriptor", "gamma");
telsoa014fcda012018-03-09 14:13:49 +0000734
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100735 const TensorInfo& mean = m_Mean->GetTensorInfo();
736 const TensorInfo& variance = m_Variance->GetTensorInfo();
737 const TensorInfo& beta = m_Beta->GetTensorInfo();
738 const TensorInfo& gamma = m_Gamma->GetTensorInfo();
telsoa014fcda012018-03-09 14:13:49 +0000739
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100740 ValidateTensorNumDimensions(mean, "BatchNormalizationQueueDescriptor", 1, "mean");
741 ValidateTensorNumDimensions(variance, "BatchNormalizationQueueDescriptor", 1, "variance");
742 ValidateTensorNumDimensions(beta, "BatchNormalizationQueueDescriptor", 1, "beta");
743 ValidateTensorNumDimensions(gamma, "BatchNormalizationQueueDescriptor", 1, "gamma");
telsoa014fcda012018-03-09 14:13:49 +0000744
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100745 ValidateTensorShapesMatch(mean, variance, "BatchNormalizationQueueDescriptor", "mean", "variance");
746 ValidateTensorShapesMatch(mean, beta, "BatchNormalizationQueueDescriptor", "mean", "beta");
747 ValidateTensorShapesMatch(mean, gamma, "BatchNormalizationQueueDescriptor", "mean", "gamma");
telsoa014fcda012018-03-09 14:13:49 +0000748}
749
750void Convolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
751{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100752 ValidateNumInputs(workloadInfo, "Convolution2dQueueDescriptor", 1);
753 ValidateNumOutputs(workloadInfo, "Convolution2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000754
755 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "Convolution2dQueueDescriptor", 4, "input");
756 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "Convolution2dQueueDescriptor", 4, "output");
757
758 ValidatePointer(m_Weight, "Convolution2dQueueDescriptor", "weight");
759 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "Convolution2dQueueDescriptor", 4, "weight");
760 ValidateTensorDataType(m_Weight->GetTensorInfo(), workloadInfo.m_InputTensorInfos[0].GetDataType(),
761 "Convolution2dQueueDescriptor", "weight");
762 if (m_Parameters.m_BiasEnabled)
763 {
764 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "Convolution2dQueueDescriptor", 1, "bias");
765 ValidateTensorDataType(m_Bias->GetTensorInfo(),
766 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
767 "Convolution2dQueueDescriptor", "bias");
768 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
769 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "Convolution2dQueueDescriptor");
770 }
771
772 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
773 workloadInfo.m_OutputTensorInfos[0], "Convolution2dQueueDescriptor", "input", "weights", "output");
774}
775
776void DepthwiseConvolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
777{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100778 ValidateNumInputs(workloadInfo, "DepthwiseConvolution2dQueueDescriptor", 1);
779 ValidateNumOutputs(workloadInfo, "DepthwiseConvolution2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000780
781 ValidateTensorNumDimensions(
782 workloadInfo.m_InputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", 4, "input");
783 ValidateTensorNumDimensions(
784 workloadInfo.m_OutputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", 4, "output");
785
786 ValidatePointer(m_Weight, "DepthwiseConvolution2dQueueDescriptor", "weight");
787 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 4, "weight");
788
Bruno Goncalves22972f02019-04-26 21:03:24 -0300789 if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 )
790 {
791 throw InvalidArgumentException(
792 boost::str(boost::format("DepthwiseConvolution2dQueueDescriptor: dilationX (provided %1%) "
793 "and dilationY (provided %2%) cannot be smaller than 1.")
794 % m_Parameters.m_DilationX % m_Parameters.m_DilationX));
795 }
796
Nikhil Rajcec6b652018-10-12 13:51:57 +0100797 const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
798
Matteo Martincigh747ef822018-12-18 09:26:39 +0000799 // Expected weight shape: [ M, I, H, W ] - This shape does NOT depend on the data layout
800 // inputChannels * channelMultiplier should be equal to outputChannels.
telsoa014fcda012018-03-09 14:13:49 +0000801 const unsigned int numWeightChannelMultiplier = m_Weight->GetTensorInfo().GetShape()[0];
Matteo Martincigh747ef822018-12-18 09:26:39 +0000802 const unsigned int numWeightInputChannels = m_Weight->GetTensorInfo().GetShape()[1];
Nikhil Rajcec6b652018-10-12 13:51:57 +0100803 const unsigned int numWeightOutputChannels = workloadInfo.m_OutputTensorInfos[0].GetShape()[channelIndex];
telsoa014fcda012018-03-09 14:13:49 +0000804 if (numWeightChannelMultiplier * numWeightInputChannels != numWeightOutputChannels)
805 {
806 throw InvalidArgumentException(
807 boost::str(boost::format("DepthwiseConvolution2dQueueDescriptor: output_channels (provided %1%) should be "
808 "equal to input_channels (provided %2%) multiplied by channel_multiplier "
809 "(provided %3%).")
810 % numWeightOutputChannels % numWeightInputChannels % numWeightChannelMultiplier));
811 }
812
813 if (m_Parameters.m_BiasEnabled)
814 {
815 ValidatePointer(m_Bias, "DepthwiseConvolution2dQueueDescriptor", "bias");
816 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 1, "bias");
817 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
818 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor");
819
820 ValidateTensorDataType(m_Bias->GetTensorInfo(),
821 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
822 "DepthwiseConvolution2dQueueDescriptor", "bias");
823 }
824
825 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
826 workloadInfo.m_OutputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", "input", "weights", "output");
Ruomei Yan88d44b82019-05-23 14:29:06 +0100827
828 // Check the supported data types
829 std::vector<DataType> supportedTypes = {
830 DataType::Float32,
831 DataType::QuantisedAsymm8,
832 DataType::QuantisedSymm16,
833 DataType::Float16
834 };
835
836 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
837 supportedTypes,
838 "DepthwiseConvolution2dQueueDescriptor");
839
840 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
841 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
842 "DepthwiseConvolution2dQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000843}
844
845void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
846{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100847 ValidateNumInputs(workloadInfo, "PermuteQueueDescriptor", 1);
848 ValidateNumOutputs(workloadInfo, "PermuteQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000849
850 const PermutationVector& mapping = m_Parameters.m_DimMappings;
851
852 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
853 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
854
855 ValidateTensorNumDimensions(input, "PermuteQueueDescriptor", mapping.GetSize(), "input");
856 ValidateTensorNumDimensions(output, "PermuteQueueDescriptor", mapping.GetSize(), "output");
857
858 for (unsigned int i = 0; i < mapping.GetSize(); ++i)
859 {
860 if (input.GetShape()[i] != output.GetShape()[mapping[i]])
861 {
862 throw InvalidArgumentException("PermuteQueueDescriptor: src dimension " + to_string(i) +
863 " (=" + to_string(input.GetShape()[i]) + ") " +
864 "must match dst dimension " + to_string(mapping[i]) +
865 " (=" + to_string(output.GetShape()[mapping[i]]) + ")");
866 }
867 }
868}
869
870void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
871{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100872 ValidateNumInputs(workloadInfo, "Pooling2dQueueDescriptor", 1);
873 ValidateNumOutputs(workloadInfo, "Pooling2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000874
875 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "Pooling2dQueueDescriptor", 4, "input");
876 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "Pooling2dQueueDescriptor", 4, "output");
Teresa Charlina3b20472019-06-06 11:12:32 +0100877
878 std::vector<DataType> supportedTypes =
879 {
880 DataType::Float32,
881 DataType::Float16,
Teresa Charlin0434df62019-06-06 13:40:35 +0100882 DataType::QuantisedAsymm8,
883 DataType::QuantisedSymm16
Teresa Charlina3b20472019-06-06 11:12:32 +0100884 };
885
886 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
887 supportedTypes,
888 "Pooling2dQueueDescriptor");
889
890 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
891 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
892 "Pooling2dQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000893}
894
895void ResizeBilinearQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
896{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100897 ValidateNumInputs(workloadInfo, "ResizeBilinearQueueDescriptor", 1);
898 ValidateNumOutputs(workloadInfo, "ResizeBilinearQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000899
900 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "ResizeBilinearQueueDescriptor", 4, "input");
901 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "ResizeBilinearQueueDescriptor", 4, "output");
902
telsoa01c577f2c2018-08-31 09:22:23 +0100903 // Resizes bilinear only changes width and height: batch and channel count must match.
telsoa014fcda012018-03-09 14:13:49 +0000904 {
905 const unsigned int inputBatchSize = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
906 const unsigned int outputBatchSize = workloadInfo.m_OutputTensorInfos[0].GetShape()[0];
907 if (inputBatchSize != outputBatchSize)
908 {
909 throw InvalidArgumentException(
910 boost::str(boost::format("ResizeBilinearQueueDescriptor: Input batch size (%1%) "
911 "does not match output batch size (%2%)") % inputBatchSize % outputBatchSize));
912 }
913 }
914
915 {
Matthew Bentham8800c002018-11-19 13:19:28 +0000916 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
James Conroy59540822018-10-11 12:39:05 +0100917 const unsigned int inputChannelCount =
Matthew Bentham8800c002018-11-19 13:19:28 +0000918 workloadInfo.m_InputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
James Conroy59540822018-10-11 12:39:05 +0100919 const unsigned int outputChannelCount =
Matthew Bentham8800c002018-11-19 13:19:28 +0000920 workloadInfo.m_OutputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
telsoa014fcda012018-03-09 14:13:49 +0000921 if (inputChannelCount != outputChannelCount)
922 {
923 throw InvalidArgumentException(
924 boost::str(boost::format("ResizeBilinearQueueDescriptor: Input channel count (%1%) "
925 "does not match output channel count (%2%)") % inputChannelCount % outputChannelCount));
926 }
927 }
928}
929
930void FakeQuantizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
931{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100932 ValidateNumInputs(workloadInfo, "FakeQuantizationQueueDescriptor", 1);
933 ValidateNumOutputs(workloadInfo, "FakeQuantizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000934
935 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "FakeQuantizationQueueDescriptor", 2, "input");
936 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "FakeQuantizationQueueDescriptor", 2, "output");
937 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
938 workloadInfo.m_OutputTensorInfos[0],
939 "FakeQuantizationQueueDescriptor",
940 "input",
941 "output");
942 if (m_Parameters.m_Min > m_Parameters.m_Max)
943 {
944 throw InvalidArgumentException("FakeQuantizationQueueDescriptor: min cannot be greater than max");
945 }
946
947}
948
949void L2NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
950{
Ferran Balaguerd73d14f2019-06-10 10:29:54 +0100951 const std::string& descriptorName = "L2NormalizationQueueDescriptor";
telsoa014fcda012018-03-09 14:13:49 +0000952
Ferran Balaguerd73d14f2019-06-10 10:29:54 +0100953 ValidateNumInputs(workloadInfo, descriptorName, 1);
954 ValidateNumOutputs(workloadInfo, descriptorName, 1);
955
956 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], descriptorName, 4, "input");
957 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], descriptorName, 4, "output");
telsoa014fcda012018-03-09 14:13:49 +0000958 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
959 workloadInfo.m_OutputTensorInfos[0],
Ferran Balaguerd73d14f2019-06-10 10:29:54 +0100960 descriptorName,
telsoa014fcda012018-03-09 14:13:49 +0000961 "input",
962 "output");
Ferran Balaguerd73d14f2019-06-10 10:29:54 +0100963
964 // Check the supported data types
965 std::vector<DataType> supportedTypes =
966 {
967 DataType::Float32,
968 DataType::Float16,
969 DataType::QuantisedAsymm8,
970 DataType::QuantisedSymm16
971 };
972
973 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
974 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, descriptorName);
975 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
976 {workloadInfo.m_InputTensorInfos[0].GetDataType()}, descriptorName);
telsoa014fcda012018-03-09 14:13:49 +0000977}
978
979void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
980{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100981 ValidateNumInputs(workloadInfo, "ConstantQueueDescriptor", 0);
982 ValidateNumOutputs(workloadInfo, "ConstantQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000983
984 if (!m_LayerOutput)
985 {
986 throw InvalidArgumentException("ConstantQueueDescriptor: No const input specified");
987 }
988
989 ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(),
990 workloadInfo.m_OutputTensorInfos[0],
991 "ConstantQueueDescriptor",
992 "constant",
993 "output");
Nina Drozd58ef2c62019-05-16 12:09:18 +0100994
995 // Check the supported data types
996 std::vector<DataType> supportedTypes =
Nina Drozd2f2778f2019-05-27 10:37:05 +0100997 {
998 DataType::Float32,
999 DataType::Float16,
1000 DataType::Signed32,
1001 DataType::QuantisedAsymm8,
1002 DataType::QuantisedSymm16
1003 };
Nina Drozd58ef2c62019-05-16 12:09:18 +01001004
1005 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, "ConstantQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +00001006}
1007
1008void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1009{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001010 ValidateNumInputs(workloadInfo, "ReshapeQueueDescriptor", 1);
1011 ValidateNumOutputs(workloadInfo, "ReshapeQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +00001012
1013 if (workloadInfo.m_InputTensorInfos[0].GetNumElements() != workloadInfo.m_OutputTensorInfos[0].GetNumElements())
1014 {
1015 throw InvalidArgumentException("ReshapeQueueDescriptor: Input tensor has " +
1016 to_string(workloadInfo.m_InputTensorInfos[0].GetNumElements()) + " but output tensor has " +
1017 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
1018 }
Nina Drozd2f2778f2019-05-27 10:37:05 +01001019
1020 // Check the supported data types
1021 std::vector<DataType> supportedTypes =
1022 {
1023 DataType::Float32,
1024 DataType::Float16,
Nina Drozd8ed4b8c2019-05-29 10:41:04 +01001025 DataType::QuantisedAsymm8,
1026 DataType::QuantisedSymm16
Nina Drozd2f2778f2019-05-27 10:37:05 +01001027 };
1028
1029 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, "ReshapeQueueDescriptor");
1030 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, "ReshapeQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +00001031}
1032
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001033void SpaceToBatchNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1034{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001035 ValidateNumInputs(workloadInfo, "SpaceToBatchNdQueueDescriptor", 1);
1036 ValidateNumOutputs(workloadInfo, "SpaceToBatchNdQueueDescriptor", 1);
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001037
1038 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "SpaceToBatchNdQueueDescriptor", 4, "input");
1039 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "SpaceToBatchNdQueueDescriptor", 4, "output");
1040
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001041 if (m_Parameters.m_BlockShape.size() != 2)
1042 {
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001043 throw InvalidArgumentException("Block Shape must contain 2 spatial dimensions");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001044 }
1045
1046 if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
1047 {
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001048 throw InvalidArgumentException("Pad List must contain the same number of dimensions as Block Shape.");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001049 }
1050
1051 const TensorShape inputShape = workloadInfo.m_InputTensorInfos[0].GetShape();
1052
1053 std::pair<unsigned int, unsigned int> heightPad = m_Parameters.m_PadList[0];
1054 std::pair<unsigned int, unsigned int> widthPad = m_Parameters.m_PadList[1];
1055
Matthew Bentham8800c002018-11-19 13:19:28 +00001056 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1057 unsigned int inputHeight = inputShape[dimensionIndices.GetHeightIndex()]
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001058 + heightPad.first + heightPad.second;
1059
Matthew Bentham8800c002018-11-19 13:19:28 +00001060 unsigned int inputWidth = inputShape[dimensionIndices.GetWidthIndex()]
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001061 + widthPad.first + widthPad.second;
1062
1063 unsigned int numInputElements = inputShape[0] * inputHeight * inputWidth
Matthew Bentham8800c002018-11-19 13:19:28 +00001064 * inputShape[dimensionIndices.GetChannelsIndex()];
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001065
1066 if (workloadInfo.m_OutputTensorInfos[0].GetNumElements() != numInputElements)
1067 {
1068 throw InvalidArgumentException("SpaceToBatchNdQueueDescriptor: Input tensor has " +
1069 to_string(numInputElements) + " after padding but output tensor has " +
1070 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
1071 }
1072
1073 if (inputHeight % m_Parameters.m_BlockShape[0] != 0 || inputWidth % m_Parameters.m_BlockShape[1] != 0)
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001074 {
1075 throw InvalidArgumentException(
1076 "Input shape after padding must be divisible by Block Shape in all spatial dimensions");
1077 }
nikraj01120522a2019-05-31 11:33:07 +01001078
1079 std::vector<DataType> supportedTypes =
1080 {
1081 DataType::Float16,
1082 DataType::Float32,
1083 DataType::QuantisedAsymm8,
1084 DataType::QuantisedSymm16
1085 };
1086
1087 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1088 supportedTypes,
1089 "SpaceToBatchNdQueueDescriptor");
1090
1091 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1092 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
1093 "SpaceToBatchNdQueueDescriptor");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001094}
1095
telsoa014fcda012018-03-09 14:13:49 +00001096void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1097{
James Conroy83735b12019-05-30 16:36:59 +01001098 const std::string floorQueueDescString = "FloorQueueDescriptor";
1099
1100 ValidateNumInputs(workloadInfo, floorQueueDescString, 1);
1101 ValidateNumOutputs(workloadInfo, floorQueueDescString, 1);
1102
1103 std::vector<DataType> supportedTypes =
1104 {
James Conroyb40d7102019-06-04 12:32:09 +01001105 DataType::Float32,
1106 DataType::QuantisedSymm16
James Conroy83735b12019-05-30 16:36:59 +01001107 };
1108
1109 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, floorQueueDescString);
1110 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, floorQueueDescString);
telsoa014fcda012018-03-09 14:13:49 +00001111
1112 if (workloadInfo.m_InputTensorInfos[0] != workloadInfo.m_OutputTensorInfos[0])
1113 {
James Conroy83735b12019-05-30 16:36:59 +01001114 throw InvalidArgumentException(floorQueueDescString + ": Input and output tensor infos do not match.");
telsoa014fcda012018-03-09 14:13:49 +00001115 }
1116}
1117
telsoa01c577f2c2018-08-31 09:22:23 +01001118void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1119{
1120 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "LstmQueueDescriptor", 2, "input");
1121 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "LstmQueueDescriptor", 2, "output");
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001122
1123 std::vector<DataType> supportedTypes = {
Conor Kennedyb9971c92019-05-07 07:14:23 +01001124 DataType::Float16,
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001125 DataType::Float32,
Conor Kennedyb9971c92019-05-07 07:14:23 +01001126 DataType::QuantisedSymm16
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001127 };
1128
1129 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1130 supportedTypes,
1131 "LstmQueueDescriptor");
1132
1133 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1134 supportedTypes,
1135 "LstmQueueDescriptor");
telsoa01c577f2c2018-08-31 09:22:23 +01001136}
1137
1138void ConvertFp32ToFp16QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1139{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001140 ValidateNumInputs(workloadInfo, "ConvertFp32ToFp16QueueDescriptor", 1);
1141 ValidateNumOutputs(workloadInfo, "ConvertFp32ToFp16QueueDescriptor", 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001142
1143 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float32)
1144 {
1145 throw InvalidArgumentException("ConvertFp32ToFp16QueueDescriptor: Input tensor type must be Float32.");
1146 }
1147
1148 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float16)
1149 {
1150 throw InvalidArgumentException("ConvertFp32ToFp16QueueDescriptor: Output tensor type must be Float16.");
1151 }
1152
1153 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1154 workloadInfo.m_OutputTensorInfos[0],
1155 "ConvertFp32ToFp16QueueDescriptor",
1156 "input",
1157 "output");
1158}
1159
1160void ConvertFp16ToFp32QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1161{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001162 ValidateNumInputs(workloadInfo, "ConvertFp16ToFp32QueueDescriptor", 1);
1163 ValidateNumOutputs(workloadInfo, "ConvertFp16ToFp32QueueDescriptor", 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001164
1165 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float16)
1166 {
1167 throw InvalidArgumentException("ConvertFp16ToFp32QueueDescriptor: Input tensor type must be Float16.");
1168 }
1169 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float32)
1170 {
1171 throw InvalidArgumentException("ConvertFp16ToFp32QueueDescriptor: Output tensor type must be Float32.");
1172 }
1173
1174 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1175 workloadInfo.m_OutputTensorInfos[0],
1176 "ConvertFp16ToFp32QueueDescriptor",
1177 "input",
1178 "output");
1179}
1180
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001181void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1182{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001183 ValidateNumInputs(workloadInfo, "DivisionQueueDescriptor", 2);
1184 ValidateNumOutputs(workloadInfo, "DivisionQueueDescriptor", 1);
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001185
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001186 std::vector<DataType> supportedTypes = {
1187 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001188 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +01001189 DataType::QuantisedSymm16,
1190 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001191 };
1192
1193 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1194 supportedTypes,
1195 "DivisionQueueDescriptor");
1196
1197 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1198 supportedTypes,
1199 "DivisionQueueDescriptor");
1200
1201 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1202 supportedTypes,
1203 "DivisionQueueDescriptor");
1204
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001205 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1206 workloadInfo.m_InputTensorInfos[1],
1207 workloadInfo.m_OutputTensorInfos[0],
1208 "DivisionQueueDescriptor",
1209 "first input",
1210 "second input");
1211}
1212
David Beckc2044fe2018-09-05 15:00:38 +01001213void SubtractionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1214{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001215 ValidateNumInputs(workloadInfo, "SubtractionQueueDescriptor", 2);
1216 ValidateNumOutputs(workloadInfo, "SubtractionQueueDescriptor", 1);
David Beckc2044fe2018-09-05 15:00:38 +01001217
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001218 std::vector<DataType> supportedTypes = {
1219 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001220 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +01001221 DataType::QuantisedSymm16,
1222 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001223 };
1224
1225 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1226 supportedTypes,
1227 "SubtractionQueueDescriptor");
1228
1229 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1230 supportedTypes,
1231 "SubtractionQueueDescriptor");
1232
1233 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1234 supportedTypes,
1235 "SubtractionQueueDescriptor");
1236
David Beckc2044fe2018-09-05 15:00:38 +01001237 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1238 workloadInfo.m_InputTensorInfos[1],
1239 workloadInfo.m_OutputTensorInfos[0],
1240 "SubtractionQueueDescriptor",
1241 "first input",
1242 "second input");
1243}
1244
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001245void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1246{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001247 ValidateNumInputs(workloadInfo, "MaximumQueueDescriptor", 2);
1248 ValidateNumOutputs(workloadInfo, "MaximumQueueDescriptor", 1);
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001249
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001250 std::vector<DataType> supportedTypes = {
1251 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001252 DataType::QuantisedAsymm8,
1253 DataType::QuantisedSymm16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001254 };
1255
1256 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1257 supportedTypes,
1258 "MaximumQueueDescriptor");
1259
1260 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1261 supportedTypes,
1262 "MaximumQueueDescriptor");
1263
1264 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1265 supportedTypes,
1266 "MaximumQueueDescriptor");
1267
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001268 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1269 workloadInfo.m_InputTensorInfos[1],
1270 workloadInfo.m_OutputTensorInfos[0],
1271 "MaximumQueueDescriptor",
1272 "first input",
1273 "second input");
1274}
1275
narpra01a6bf9122018-09-10 09:50:09 +01001276void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1277{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001278 ValidateNumInputs(workloadInfo, "MeanQueueDescriptor", 1);
1279 ValidateNumOutputs(workloadInfo, "MeanQueueDescriptor", 1);
narpra01eb061912018-09-10 17:35:27 +01001280
1281 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
1282 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1283
narpra0132b90462018-09-13 11:07:48 +01001284 if (m_Parameters.m_KeepDims)
narpra01eb061912018-09-10 17:35:27 +01001285 {
1286 ValidateTensorNumDimensions(output, "MeanQueueDescriptor", input.GetNumDimensions(), "output");
1287 }
narpra0132b90462018-09-13 11:07:48 +01001288 else if (m_Parameters.m_Axis.empty())
narpra01eb061912018-09-10 17:35:27 +01001289 {
1290 ValidateTensorNumDimensions(output, "MeanQueueDescriptor", 1, "output");
1291 }
1292 else
1293 {
narpra0132b90462018-09-13 11:07:48 +01001294 auto outputDim = input.GetNumDimensions() - boost::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
narpra01eb061912018-09-10 17:35:27 +01001295 ValidateTensorNumDimensions(output,
1296 "MeanQueueDescriptor",
1297 outputDim > 0 ? outputDim : 1,
1298 "output");
1299 }
narpra01a6bf9122018-09-10 09:50:09 +01001300}
1301
jimfly012c9322a2018-09-19 10:59:49 +01001302void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1303{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001304 ValidateNumInputs(workloadInfo, "PadQueueDescriptor", 1);
1305 ValidateNumOutputs(workloadInfo, "PadQueueDescriptor", 1);
jimfly012c9322a2018-09-19 10:59:49 +01001306
1307 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
Nina Drozd661dfa72018-10-02 11:14:17 +01001308 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1309
jimfly012c9322a2018-09-19 10:59:49 +01001310 // input and output should have the same number of dimensions
1311 ValidateTensorNumDimensions(output, "PadQueueDescriptor", input.GetNumDimensions(), "output");
1312 // there should be entry in the pad list for each dimension in the input tensor
1313 if (m_Parameters.m_PadList.size() != input.GetNumDimensions()) {
1314 throw InvalidArgumentException("Pad List should contain the same number of entries as there"
1315 " are dimensions in the input tensor that is " +
1316 to_string(input.GetNumDimensions()) + " entries " +
1317 " not " + to_string(m_Parameters.m_PadList.size()) + " entries.");
1318 }
1319}
1320
Derek Lambertia9cca6a2019-03-25 15:41:58 +00001321void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1322{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001323 ValidateNumInputs(workloadInfo, "QuantizeQueueDescriptor", 1);
1324 ValidateNumOutputs(workloadInfo, "QuantizeQueueDescriptor", 1);
Derek Lambertia9cca6a2019-03-25 15:41:58 +00001325
1326
1327 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float32)
1328 {
1329 throw InvalidArgumentException("Quantize only accepts Float32 inputs.");
1330 }
1331
1332 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::QuantisedAsymm8 &&
1333 workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::QuantisedSymm16)
1334 {
1335 throw InvalidArgumentException("Output of quantized layer must be quantized type.");
1336 }
1337}
1338
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +00001339void BatchToSpaceNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1340{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001341 ValidateNumInputs(workloadInfo, "BatchToSpaceNdQueueDescriptor", 1);
1342 ValidateNumOutputs(workloadInfo, "BatchToSpaceNdQueueDescriptor", 1);
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +00001343}
1344
Conor Kennedy430b5d82018-11-14 15:28:28 +00001345void StridedSliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1346{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001347 ValidateNumInputs(workloadInfo, "StridedSliceQueueDescriptor", 1);
1348 ValidateNumOutputs(workloadInfo, "StridedSliceQueueDescriptor", 1);
Conor Kennedy430b5d82018-11-14 15:28:28 +00001349
1350 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
Matteo Martincighe851b3d2019-05-28 14:31:20 +01001351 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1352
1353 std::vector<DataType> supportedTypes =
1354 {
1355 DataType::Float16,
1356 DataType::Float32,
Matteo Martincigh42666a12019-05-29 08:53:41 +01001357 DataType::QuantisedAsymm8,
1358 DataType::QuantisedSymm16
Matteo Martincighe851b3d2019-05-28 14:31:20 +01001359 };
1360
1361 ValidateDataTypes(input, supportedTypes, "StridedSliceQueueDescriptor");
1362 ValidateDataTypes(output, supportedTypes, "StridedSliceQueueDescriptor");
1363
1364 ValidateDataTypes(output, { input.GetDataType() }, "StridedSliceQueueDescriptor");
1365
1366 ValidateTensorQuantizationSpace(input, output, "StridedSliceQueueDescriptor", "input", "output");
1367
Conor Kennedy430b5d82018-11-14 15:28:28 +00001368 const uint32_t rank = input.GetNumDimensions();
1369
Nattapat Chaimanowonga0d28442018-11-21 16:48:17 +00001370 if (rank > 4)
1371 {
1372 throw InvalidArgumentException(
1373 "StridedSliceLayer: Input tensors with rank greater than 4 are not supported");
1374 }
1375
Conor Kennedy430b5d82018-11-14 15:28:28 +00001376 // Begin, End & Stride length must be of rank(input0)
1377 if (m_Parameters.m_Begin.size() != rank)
1378 {
1379 throw InvalidArgumentException("StridedSliceLayer: Begin length must be of rank input0("
1380 + to_string(rank) + ")");
1381 }
1382
1383 if (m_Parameters.m_End.size() != rank)
1384 {
1385 throw InvalidArgumentException("StridedSliceLayer: End length must be of rank input0("
1386 + to_string(rank) + ")");
1387 }
1388
1389 if (m_Parameters.m_Stride.size() != rank)
1390 {
1391 throw InvalidArgumentException("StridedSliceLayer: Stride length must be of rank input0("
1392 + to_string(rank) + ")");
1393 }
1394
1395 // Stride entries must be non-zero
1396 for (auto& stride : m_Parameters.m_Stride)
1397 {
1398 if (stride == 0)
1399 {
1400 throw InvalidArgumentException("StridedSliceLayer: Stride entries must be non-zero");
1401 }
1402 }
1403}
1404
kevmay0190539692018-11-29 08:40:19 +00001405void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1406{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001407 ValidateNumInputs(workloadInfo, "MinimumQueueDescriptor", 2);
1408 ValidateNumOutputs(workloadInfo, "MinimumQueueDescriptor", 1);
kevmay0190539692018-11-29 08:40:19 +00001409
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001410 std::vector<DataType> supportedTypes = {
1411 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001412 DataType::QuantisedAsymm8,
1413 DataType::QuantisedSymm16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001414 };
1415
1416 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1417 supportedTypes,
1418 "MinimumQueueDescriptor");
1419
1420 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1421 supportedTypes,
1422 "MinimumQueueDescriptor");
1423
1424 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1425 supportedTypes,
1426 "MinimumQueueDescriptor");
1427
kevmay0190539692018-11-29 08:40:19 +00001428 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1429 workloadInfo.m_InputTensorInfos[1],
1430 workloadInfo.m_OutputTensorInfos[0],
1431 "MinimumQueueDescriptor",
1432 "first input",
1433 "second input");
1434}
1435
Nattapat Chaimanowonga9a1cf12018-12-03 16:06:49 +00001436void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1437{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001438 ValidateNumInputs(workloadInfo, "DebugQueueDescriptor", 1);
1439 ValidateNumOutputs(workloadInfo, "DebugQueueDescriptor", 1);
Nattapat Chaimanowonga9a1cf12018-12-03 16:06:49 +00001440}
1441
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001442void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1443{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001444 ValidateNumInputs(workloadInfo, "EqualQueueDescriptor", 2);
1445 ValidateNumOutputs(workloadInfo, "EqualQueueDescriptor", 1);
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001446
1447 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1448 workloadInfo.m_InputTensorInfos[1],
1449 workloadInfo.m_OutputTensorInfos[0],
1450 "EqualQueueDescriptor",
1451 "first input",
1452 "second input");
kevmay012b4d88e2019-01-24 14:05:09 +00001453
1454 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
1455 {
1456 throw InvalidArgumentException("EqualQueueDescriptor: Output tensor type must be Boolean.");
1457 }
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001458}
1459
FrancisMurtagh878f0232018-12-19 10:56:15 +00001460void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1461{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001462 ValidateNumInputs(workloadInfo, "GreaterQueueDescriptor", 2);
1463 ValidateNumOutputs(workloadInfo, "GreaterQueueDescriptor", 1);
FrancisMurtagh878f0232018-12-19 10:56:15 +00001464
1465 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1466 workloadInfo.m_InputTensorInfos[1],
1467 workloadInfo.m_OutputTensorInfos[0],
1468 "GreaterQueueDescriptor",
1469 "first input",
1470 "second input");
kevmay012b4d88e2019-01-24 14:05:09 +00001471
1472 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
1473 {
1474 throw InvalidArgumentException("GreaterQueueDescriptor: Output tensor type must be Boolean.");
1475 }
FrancisMurtagh878f0232018-12-19 10:56:15 +00001476}
1477
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001478void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1479{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001480 ValidateNumInputs(workloadInfo, "RsqrtQueueDescriptor", 1);
1481 ValidateNumOutputs(workloadInfo, "RsqrtQueueDescriptor", 1);
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001482 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1483 workloadInfo.m_OutputTensorInfos[0],
1484 "RsqrtQueueDescriptor",
1485 "input",
1486 "output");
nikraj010421e7f2019-06-14 09:40:34 +01001487
1488 std::vector<DataType> supportedTypes =
1489 {
1490 DataType::Float16,
1491 DataType::Float32,
nikraj0124d73212019-06-14 14:20:40 +01001492 DataType::QuantisedAsymm8,
1493 DataType::QuantisedSymm16
nikraj010421e7f2019-06-14 09:40:34 +01001494 };
1495
1496 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1497 supportedTypes,
1498 "RsqrtQueueDescriptor");
1499
1500 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1501 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
1502 "RsqrtQueueDescriptor");
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001503}
1504
narpra01b89b05f2019-01-16 09:53:09 +00001505void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1506{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001507 ValidateNumInputs(workloadInfo, "GatherQueueDescriptor", 2);
1508 ValidateNumOutputs(workloadInfo, "GatherQueueDescriptor", 1);
narpra014951d842019-01-18 16:53:53 +00001509
1510 const TensorInfo& indices = workloadInfo.m_InputTensorInfos[1];
1511
1512 if (indices.GetDataType() != DataType::Signed32)
1513 {
1514 throw InvalidArgumentException("GatherQueueDescriptor: Indices tensor type must be int32.");
1515 }
1516
1517 const TensorInfo& params = workloadInfo.m_InputTensorInfos[0];
1518 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1519 unsigned int paramsDim = params.GetNumDimensions();
1520 unsigned int indicesDim = indices.GetNumDimensions();
1521 unsigned int outputDim = paramsDim - 1 + indicesDim;
1522
1523 ValidateTensorNumDimensions(output, "GatherQueueDescriptor", outputDim, "output");
narpra01b89b05f2019-01-16 09:53:09 +00001524}
1525
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001526void DetectionPostProcessQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1527{
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001528 const std::string& descriptorName = " DetectionPostProcessQueueDescriptor";
1529 ValidateNumInputs(workloadInfo, descriptorName, 2);
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001530
1531 if (workloadInfo.m_OutputTensorInfos.size() != 4)
1532 {
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001533 throw InvalidArgumentException(descriptorName + ": Requires exactly four outputs. " +
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001534 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
1535 }
1536
1537 if (m_Anchors == nullptr)
1538 {
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001539 throw InvalidArgumentException(descriptorName + ": Anchors tensor descriptor is missing.");
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001540 }
1541
1542 const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001543 const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
1544 const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
1545
1546 const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
Narumol Prangnawarat6d302bf2019-02-04 11:46:26 +00001547 const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001548 const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
1549 const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001550
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001551 ValidateTensorNumDimensions(boxEncodingsInfo, descriptorName, 3, "box encodings");
1552 ValidateTensorNumDimensions(scoresInfo, descriptorName, 3, "scores");
1553 ValidateTensorNumDimensions(anchorsInfo, descriptorName, 2, "anchors");
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001554
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001555 const std::vector<DataType> supportedInputTypes =
1556 {
1557 DataType::Float32,
1558 DataType::QuantisedAsymm8,
1559 DataType::QuantisedSymm16
1560 };
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001561
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001562 ValidateDataTypes(boxEncodingsInfo, supportedInputTypes, descriptorName);
1563 ValidateDataTypes(scoresInfo, supportedInputTypes, descriptorName);
1564 ValidateDataTypes(anchorsInfo, supportedInputTypes, descriptorName);
1565
1566 ValidateTensorNumDimensions(detectionBoxesInfo, descriptorName, 3, "detection boxes");
1567 ValidateTensorNumDimensions(detectionScoresInfo, descriptorName, 2, "detection scores");
1568 ValidateTensorNumDimensions(detectionClassesInfo, descriptorName, 2, "detection classes");
1569 ValidateTensorNumDimensions(numDetectionsInfo, descriptorName, 1, "num detections");
1570
1571 // NOTE: Output is always Float32 regardless of input type
1572 ValidateTensorDataType(detectionBoxesInfo, DataType::Float32, descriptorName, "detection boxes");
1573 ValidateTensorDataType(detectionScoresInfo, DataType::Float32, descriptorName, "detection scores");
1574 ValidateTensorDataType(detectionClassesInfo, DataType::Float32, descriptorName, "detection classes");
1575 ValidateTensorDataType(numDetectionsInfo, DataType::Float32, descriptorName, "num detections");
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001576
1577 if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f)
1578 {
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001579 throw InvalidArgumentException(descriptorName + ": Intersection over union threshold "
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001580 "must be positive and less than or equal to 1.");
1581 }
1582 if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
1583 {
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001584 throw InvalidArgumentException(descriptorName + ": Number of classes with background "
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001585 "should be equal to number of classes + 1.");
1586 }
1587}
1588
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00001589void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1590{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001591 ValidateNumInputs(workloadInfo, "DequantizeQueueDescriptor", 1);
1592 ValidateNumOutputs(workloadInfo, "DequantizeQueueDescriptor", 1);
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00001593
1594 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::QuantisedAsymm8 &&
1595 workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::QuantisedSymm16)
1596 {
1597 throw InvalidArgumentException("Input to dequantize layer must be quantized type.");
1598 }
1599
1600 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float32)
1601 {
1602 throw InvalidArgumentException("Output of dequantize layer must be Float32 type.");
1603 }
1604}
1605
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001606void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1607{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001608 ValidateNumInputs(workloadInfo, "MergeQueueDescriptor", 2);
1609 ValidateNumOutputs(workloadInfo, "MergeQueueDescriptor", 1);
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001610
1611 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1612 workloadInfo.m_InputTensorInfos[1],
1613 "MergeQueueDescriptor",
1614 "input0",
1615 "input1");
1616
1617 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1618 workloadInfo.m_OutputTensorInfos[0],
1619 "MergeQueueDescriptor",
1620 "input0",
1621 "output");
1622
1623 const DataType dataType = workloadInfo.m_InputTensorInfos[0].GetDataType();
1624 ValidateTensorDataType(workloadInfo.m_InputTensorInfos[1], dataType, "MergeQueueDescriptor", "input1");
1625 ValidateTensorDataType(workloadInfo.m_OutputTensorInfos[0], dataType, "MergeQueueDescriptor", "output");
1626}
1627
Sadik Armaganeff363d2019-04-05 15:25:46 +01001628void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1629{
1630 ValidateNumInputs(workloadInfo, "SwitchQueueDescriptor", 2);
1631 ValidateNumOutputs(workloadInfo, "SwitchQueueDescriptor", 2);
1632
1633 std::vector<DataType> supportedTypes = {
1634 DataType::Float32,
1635 DataType::QuantisedAsymm8,
1636 DataType::QuantisedSymm16
1637 };
1638
1639 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1640 supportedTypes,
1641 "SwitchQueueDescriptor");
1642
1643 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1644 supportedTypes,
1645 "SwitchQueueDescriptor");
1646
1647 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1648 supportedTypes,
1649 "SwitchQueueDescriptor");
1650
1651 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1652 workloadInfo.m_OutputTensorInfos[0],
1653 "SwitchQueueDescriptor",
1654 "input0",
1655 "output0");
1656
1657 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1658 workloadInfo.m_OutputTensorInfos[1],
1659 "SwitchQueueDescriptor",
1660 "input0",
1661 "output1");
1662}
1663
Matteo Martincigh49124022019-01-11 13:25:59 +00001664void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1665{
1666 // This is internally generated so it should not need validation.
1667}
1668
Nattapat Chaimanowonga0d28442018-11-21 16:48:17 +00001669} //namespace armnn