blob: 324c1debc002cb5f6c6096df3472aa064e1be93f [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//---------------------------------------------------------------
Jan Eilers38e05bd2019-06-26 13:10:09 +0100117void ValidateTensorNumElements(const TensorInfo& tensor,
118 std::string const& descName,
119 unsigned int numElements,
120 std::string const& tensorName)
121{
122 if (tensor.GetNumElements() != numElements)
123 {
124 throw InvalidArgumentException(descName + ": Expected " + to_string(numElements) + " but got " +
125 to_string(tensor.GetNumDimensions()) + " elements for " +
126 tensorName + " tensor.");
127 }
128}
129
130//---------------------------------------------------------------
131void ValidateTensorNumDimNumElem(const TensorInfo& tensorInfo,
132 unsigned int numDimension,
133 unsigned int numElements,
134 std::string const& tensorName)
135{
136 ValidateTensorNumDimensions(tensorInfo, "ValidateTensorNumDimNumElem: NumDimensionCheck", numDimension, tensorName);
137 ValidateTensorNumElements(tensorInfo, "ValidateTensorNumDimNumElem: NumElementsCheck", numElements, tensorName);
138}
139
140//---------------------------------------------------------------
telsoa014fcda012018-03-09 14:13:49 +0000141void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
142 const std::string& descName, std::string const& tensorName)
143{
144 if (tensor.GetDataType() != dataType)
145 {
146 throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
147 GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
148 }
149}
150
151//---------------------------------------------------------------
Matteo Martincighe851b3d2019-05-28 14:31:20 +0100152void ValidateTensorQuantizationSpace(const TensorInfo& first,
153 const TensorInfo& second,
154 const std::string& descName,
155 std::string const& firstName,
156 std::string const& secondName)
157{
158 if (!first.IsQuantized() ||
159 !second.IsQuantized())
160 {
161 // Not a quantized type, ignore the validation
162 return;
163 }
164
165 DataType firstDataType = first.GetDataType();
166 DataType secondDataType = second.GetDataType();
167
168 if (firstDataType != secondDataType)
169 {
170 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
171 " must be of the same quantized type, " +
172 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
173 secondName + " is " + GetDataTypeName(secondDataType));
174 }
175
176 if (!first.IsTypeSpaceMatch(second))
177 {
178 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
179 " must have the same quantization space, " +
180 firstName + " has offset " + to_string(first.GetQuantizationOffset()) +
181 " and scale " + to_string(first.GetQuantizationScale()) + ", " +
182 secondName + " has offset " + to_string(second.GetQuantizationOffset()) +
183 " and scale " + to_string(second.GetQuantizationScale()));
184 }
185}
186
187//---------------------------------------------------------------
telsoa014fcda012018-03-09 14:13:49 +0000188void ValidateBiasTensorQuantization(const TensorInfo& biasTensor, const TensorInfo& inputTensorInfo,
189 const TensorInfo& weightsTensorInfo, const std::string& descName)
190{
191 if (biasTensor.GetQuantizationOffset() != 0)
192 {
193 throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
194 to_string(biasTensor.GetQuantizationOffset()));
195 }
196 const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightsTensorInfo.GetQuantizationScale();
kevmay016c46dd32018-12-17 15:32:45 +0000197 if (std::abs(biasTensor.GetQuantizationScale() - expectedScale) > 0.00000001f)
telsoa014fcda012018-03-09 14:13:49 +0000198 {
199 // Print the float values with extra precision to see very small differences
200 std::stringstream msg;
201 msg << std::setprecision(10) << descName << ": Expected " << expectedScale <<
202 " quantization scale for bias tensor (the product of the input and weight scales), but got " <<
203 biasTensor.GetQuantizationScale();
204 throw InvalidArgumentException(msg.str());
205 }
206}
207
208//---------------------------------------------------------------
209void ValidateTensors(const std::vector<ITensorHandle*>& vec,
210 unsigned int numExpected,
211 const std::string& descName,
212 const std::string& varName)
213{
214 if (vec.empty() && numExpected > 0)
215 {
216 throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
217 }
218
219 for (unsigned int i = 0; i < numExpected; ++i)
220 {
221 if (!vec[i])
222 {
223 throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
224 }
225 }
226}
227
228//---------------------------------------------------------------
229void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
230 const TensorInfo& second,
231 const TensorInfo& output,
232 std::string const& descName,
233 std::string const& firstName,
234 std::string const& secondName)
235{
236 // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
237 // broadcasted.
238 if (first.GetNumDimensions() != second.GetNumDimensions())
239 {
240 throw InvalidArgumentException(descName + ": Tensors "
241 + firstName + " & " + secondName
242 + " must have the same number of dimensions in order to be broadcasted");
243 }
244 uint32_t numDims = first.GetNumDimensions();
245 std::vector<uint32_t> outputDims(numDims, 0u);
246 for (uint32_t i = 0; i < numDims; i++)
247 {
248 const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i];
249 const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1);
250 if (dimsNotEqual && dimsNotOne)
251 {
252 throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes");
253 }
254 outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]);
255 }
256 TensorShape broadcastShape = TensorShape(boost::numeric_cast<unsigned int>(outputDims.size()), outputDims.data());
257 if (broadcastShape != output.GetShape())
258 {
259 throw InvalidArgumentException(descName + ": The tensor shape resulting from adding "
260 + firstName + " & " + secondName
261 + " does not match the output shape");
262 }
263}
264
265//---------------------------------------------------------------
266/// Validates that the output tensor's quantization scale is greater than the product
267/// of the two input tensors' quantization scales. This is a requirement of the implementation of
268/// the quantized multiplication.
269void ValidateTensorQuantizationMultiplier(const TensorInfo& inputTensor1, const TensorInfo& inputTensor2,
270 const TensorInfo& outputTensorInfo, std::string const& descName,
271 const std::string& inputTensor1Name, const std::string& inputTensor2Name, const std::string& outputTensorName)
272{
273 if (outputTensorInfo.GetDataType() == DataType::QuantisedAsymm8)
274 {
275 if (outputTensorInfo.GetQuantizationScale() <=
276 inputTensor1.GetQuantizationScale() * inputTensor2.GetQuantizationScale())
277 {
278 std::stringstream msg;
279 msg << descName << ": Quantization scale of " << outputTensorName << " is not greater than " <<
280 "the product of the " << inputTensor1Name << " and " << inputTensor2Name << " tensors";
281 throw InvalidArgumentException(msg.str());
282 }
283 }
284}
285
Sadik Armaganeff363d2019-04-05 15:25:46 +0100286//---------------------------------------------------------------
287void ValidateDataTypes(const TensorInfo& info,
288 const std::vector<armnn::DataType>& supportedTypes,
289 std::string const& descName)
290{
291 auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
292 if (iterator == supportedTypes.end())
293 {
294 throw InvalidArgumentException(descName + ": " + " Tensor type is not supported.");
295 }
296}
297
James Conroy4d1ff582019-06-10 17:06:39 +0100298//---------------------------------------------------------------
299void ValidateTensorDataTypesMatch(const TensorInfo& first,
300 const TensorInfo& second,
301 std::string const& descName,
302 std::string const& firstName,
303 std::string const& secondName)
304{
305 if (first.GetDataType() != second.GetDataType())
306 {
307 throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
308 " must have identical data types.");
309 }
310}
311
telsoa014fcda012018-03-09 14:13:49 +0000312} //namespace
313
314void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
315 unsigned int numExpectedIn, unsigned int numExpectedOut) const
316{
317 ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
318 ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
319}
320
321//---------------------------------------------------------------
322void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
323{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100324 ValidateNumInputs(workloadInfo, "MemCopyQueueDescriptor", 1);
325 ValidateNumOutputs(workloadInfo, "MemCopyQueueDescriptor" , 1);
telsoa014fcda012018-03-09 14:13:49 +0000326
327 if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
328 {
329 throw InvalidArgumentException(boost::str(
330 boost::format("Number of input infos (%1%) does not match the number of output infos (%2%)")
331 % workloadInfo.m_InputTensorInfos.size() % workloadInfo.m_OutputTensorInfos.size()));
332 }
333
334 for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
335 {
336 if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
337 workloadInfo.m_OutputTensorInfos[i].GetNumElements())
338 {
339 throw InvalidArgumentException(boost::str(
340 boost::format("Number of elements for tensor input and output %1% does not match")
341 % i ));
342 }
343 }
344
345 if (m_Inputs.size() != m_Outputs.size())
346 {
347 throw InvalidArgumentException(boost::str(
348 boost::format("Number of inputs (%1%) does not match the number of outputs (%2%)")
349 % m_Inputs.size() % m_Outputs.size()));
350 }
351
352 for (unsigned int i = 0; i < m_Inputs.size(); ++i)
353 {
354 if (!m_Inputs[i])
355 {
356 throw InvalidArgumentException(boost::str(boost::format("Invalid null input %1%") % i));
357 }
358
359 if (!m_Outputs[i])
360 {
361 throw InvalidArgumentException(boost::str(boost::format("Invalid null output %1%") % i));
362 }
363 }
364}
365
366//---------------------------------------------------------------
367void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
368{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100369 ValidateNumInputs(workloadInfo, "ActivationQueueDescriptor", 1);
370 ValidateNumOutputs(workloadInfo, "ActivationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000371 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
372 workloadInfo.m_OutputTensorInfos[0],
373 "ActivationQueueDescriptor",
374 "input",
375 "output");
Nattapat Chaimanowongae2c5f02019-04-24 16:19:57 +0100376
377 std::vector<DataType> supportedTypes = {
378 DataType::Float32,
379 DataType::Float16,
Teresa Charlin18515e22019-04-24 10:17:46 +0100380 DataType::QuantisedAsymm8,
381 DataType::QuantisedSymm16
Nattapat Chaimanowongae2c5f02019-04-24 16:19:57 +0100382 };
383
384 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
385 supportedTypes,
386 "ActivationQueueDescriptor");
387
388 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
389 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
390 "ActivationQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000391}
392
393//---------------------------------------------------------------
394void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
395{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100396 ValidateNumInputs(workloadInfo, "SoftmaxQueueDescriptor", 1);
397 ValidateNumOutputs(workloadInfo, "SoftmaxQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000398
399 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
400 workloadInfo.m_OutputTensorInfos[0],
401 "SoftmaxQueueDescriptor",
402 "input",
403 "output");
nikraj01248683f2019-05-29 16:46:50 +0100404
405 std::vector<DataType> supportedTypes =
406 {
407 DataType::Float16,
408 DataType::Float32,
409 DataType::QuantisedAsymm8,
410 DataType::QuantisedSymm16
411 };
412
413 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
414 supportedTypes,
415 "SoftmaxQueueDescriptor");
416
417 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
418 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
419 "SoftmaxQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000420}
421
422//---------------------------------------------------------------
423void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
424{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100425 ValidateNumInputs(workloadInfo, "SplitterQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000426
Ruomei Yan25339c32019-05-28 16:48:20 +0100427 // Check the supported data types
428 std::vector<DataType> supportedTypes =
429 {
430 DataType::Float32,
431 DataType::Float16,
432 DataType::Boolean,
433 DataType::Signed32,
434 DataType::QuantisedAsymm8,
435 DataType::QuantisedSymm16
436 };
437
438 for (unsigned long i = 0; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
439 {
440 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[i],
441 supportedTypes,
442 "SplitterQueueDescriptor");
443 }
444 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
445 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
446 "SplitterQueueDescriptor");
447
telsoa014fcda012018-03-09 14:13:49 +0000448 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
449 {
450 throw InvalidArgumentException("SplitterQueueDescriptor: At least one output needs to be provided.");
451 }
452
453 if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
454 {
455 throw InvalidArgumentException(
456 "SplitterQueueDescriptor: Number of split windows "
457 "has to match number of workloadInfo.m_OutputTensorInfos. "
458 "Number of windows: " +
459 to_string(m_ViewOrigins.size()) +
460 ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
461 }
462
telsoa01c577f2c2018-08-31 09:22:23 +0100463 //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
telsoa014fcda012018-03-09 14:13:49 +0000464 std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
465 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
466 {
telsoa01c577f2c2018-08-31 09:22:23 +0100467 //Checks that the dimensionality of input is same as the split windows.
telsoa014fcda012018-03-09 14:13:49 +0000468 ViewOrigin const& e = m_ViewOrigins[w];
469 if (e.m_Origin.size() != inputDims)
470 {
471 throw InvalidArgumentException("SplitterQueueDescriptor: Window origin have to "
472 "have the same dimensionality as the input tensor. "
473 "Window origin (index: " +
474 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
475 " dimensions, the input "
476 "tensor has " +
477 to_string(inputDims) + " dimensions.");
478 }
479 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
480 {
481 if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
482 workloadInfo.m_InputTensorInfos[0].GetShape()[i])
483 {
484 throw InvalidArgumentException("SplitterQueueDescriptor: Window extent coordinates have to "
485 "be smaller or equal than the size of the input in that coord.");
486 }
487 }
488 }
489}
490
491//---------------------------------------------------------------
Jim Flynne242f2d2019-05-22 14:24:13 +0100492void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
telsoa014fcda012018-03-09 14:13:49 +0000493{
Jim Flynne242f2d2019-05-22 14:24:13 +0100494 ValidateNumOutputs(workloadInfo, "ConcatQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000495
496 if (m_Inputs.size() <= 0)
497 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100498 throw InvalidArgumentException("ConcatQueueDescriptor: At least one input needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000499 }
500 if (m_Outputs.size() <= 0)
501 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100502 throw InvalidArgumentException("ConcatQueueDescriptor: At least one output needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000503 }
504
505 if (workloadInfo.m_InputTensorInfos.size() <= 0)
506 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100507 throw InvalidArgumentException("ConcatQueueDescriptor: At least one TensorInfo input needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000508 }
509 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
510 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100511 throw InvalidArgumentException("ConcatQueueDescriptor: At least one TensorInfo output needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000512 }
513
Nikhil Raj8599a412018-11-19 14:51:07 +0000514 if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
515 {
516 throw InvalidArgumentException("Invalid Concatenation Axis provided");
517 }
518
519 if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
520 {
521 return;
522 }
523
telsoa014fcda012018-03-09 14:13:49 +0000524 if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
525 {
526 throw InvalidArgumentException(
Jim Flynne242f2d2019-05-22 14:24:13 +0100527 "ConcatQueueDescriptor: Number of split windows "
telsoa014fcda012018-03-09 14:13:49 +0000528 "has to match number of workloadInfo.m_InputTensorInfos. "
529 "Number of windows: " +
530 to_string(m_ViewOrigins.size()) +
531 ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
532 }
533
telsoa01c577f2c2018-08-31 09:22:23 +0100534 //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
telsoa014fcda012018-03-09 14:13:49 +0000535 std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
536 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
537 {
telsoa01c577f2c2018-08-31 09:22:23 +0100538 //Checks that the dimensionality of output is same as the split windows.
telsoa014fcda012018-03-09 14:13:49 +0000539 ViewOrigin const& e = m_ViewOrigins[w];
540 if (e.m_Origin.size() != outputDims)
541 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100542 throw InvalidArgumentException("ConcatQueueDescriptor: Window origin have to "
telsoa014fcda012018-03-09 14:13:49 +0000543 "have the same dimensionality as the output tensor. "
544 "Window origin (index: " +
545 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
546 " dimensions, the output "
547 "tensor has " +
548 to_string(outputDims) + " dimensions.");
549 }
telsoa01c577f2c2018-08-31 09:22:23 +0100550 //Checks that the merge windows are within the output tensor.
telsoa014fcda012018-03-09 14:13:49 +0000551 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
552 {
553 if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
554 > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
555 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100556 throw InvalidArgumentException("ConcatQueueDescriptor: Window extent coordinates have to "
telsoa014fcda012018-03-09 14:13:49 +0000557 "be smaller or equal than the size of the output in that coord.");
558 }
559 }
560 }
Jim Flynncbb66aa2019-05-15 13:03:54 +0100561
562 // Check the supported data types
563 std::vector<DataType> supportedTypes =
564 {
565 DataType::Float32,
566 DataType::Float16,
567 DataType::Boolean,
568 DataType::Signed32,
569 DataType::QuantisedAsymm8,
570 DataType::QuantisedSymm16
571 };
572
573 for (unsigned long i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
574 {
575 ValidateDataTypes(workloadInfo.m_InputTensorInfos[i],
576 supportedTypes,
Jim Flynne242f2d2019-05-22 14:24:13 +0100577 "ConcatQueueDescriptor");
Jim Flynncbb66aa2019-05-15 13:03:54 +0100578 }
579 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
580 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
Jim Flynne242f2d2019-05-22 14:24:13 +0100581 "ConcatQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000582}
583
584//---------------------------------------------------------------
585void FullyConnectedQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
586{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100587 ValidateNumInputs(workloadInfo, "FullyConnectedQueueDescriptor", 1);
588 ValidateNumOutputs(workloadInfo, "FullyConnectedQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000589 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "FullyConnectedQueueDescriptor", 2, "output");
590
591 if (!(workloadInfo.m_InputTensorInfos[0].GetNumDimensions() == 2 ||
592 workloadInfo.m_InputTensorInfos[0].GetNumDimensions() == 4))
593 {
594 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Input tensor must have 2 or 4 dimensions.");
595 }
596
597 if (m_Weight == nullptr)
598 {
599 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Weight tensor descriptor is missing.");
600 }
601
602 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "FullyConnectedQueueDescriptor", 2, "weight");
603
604 if (m_Parameters.m_BiasEnabled)
605 {
606 if (m_Bias == nullptr)
607 {
608 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Bias is enabled but "
609 "bias value tensor descriptor is missing.");
610 }
611
telsoa01c577f2c2018-08-31 09:22:23 +0100612 // Validates type and quantization values.
telsoa014fcda012018-03-09 14:13:49 +0000613 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
614 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "FullyConnectedQueueDescriptor");
615
616 ValidateTensorDataType(m_Bias->GetTensorInfo(),
617 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
618 "FullyConnectedQueueDescriptor", "bias");
619
620 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "FullyConnectedQueueDescriptor", 1, "bias");
621 }
622
623 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
624 workloadInfo.m_OutputTensorInfos[0], "FullyConnectedQueueDescriptor", "input", "weights", "output");
Francis Murtagh46c09d02019-05-28 08:15:28 +0100625
626 // Check the supported data types
627 std::vector<DataType> supportedTypes =
628 {
629 DataType::Float32,
630 DataType::Float16,
631 DataType::QuantisedAsymm8,
632 DataType::QuantisedSymm16
633 };
634
635 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
636 supportedTypes,
637 "FullyConnectedQueueDescriptor");
638
639 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
640 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
641 "FullyConnectedQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000642}
643
644//---------------------------------------------------------------
645void NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
646{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100647 ValidateNumInputs(workloadInfo, "NormalizationQueueDescriptor", 1);
648 ValidateNumOutputs(workloadInfo, "NormalizationQueueDescriptor", 1);
Matteo Martincigh2fc70c52019-06-05 14:12:48 +0100649
650 // Check the supported data types
651 std::vector<DataType> supportedTypes =
652 {
653 DataType::Float16,
654 DataType::Float32,
Matteo Martincigh6aeb7712019-06-05 17:23:29 +0100655 DataType::QuantisedAsymm8,
656 DataType::QuantisedSymm16
Matteo Martincigh2fc70c52019-06-05 14:12:48 +0100657 };
658
659 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
660 supportedTypes,
661 "NormalizationQueueDescriptor");
662
663 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
664 { workloadInfo.m_InputTensorInfos[0].GetDataType() },
665 "NormalizationQueueDescriptor");
666
telsoa014fcda012018-03-09 14:13:49 +0000667 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
668 workloadInfo.m_OutputTensorInfos[0],
669 "NormalizationQueueDescriptor",
670 "input",
671 "output");
672}
673
674void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
675{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100676 ValidateNumInputs(workloadInfo, "AdditionQueueDescriptor", 2);
677 ValidateNumOutputs(workloadInfo, "AdditionQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000678
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100679 std::vector<DataType> supportedTypes = {
680 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +0100681 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +0100682 DataType::QuantisedSymm16,
683 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100684 };
685
686 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
687 supportedTypes,
688 "AdditionQueueDescriptor");
689
690 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
691 supportedTypes,
692 "AdditionQueueDescriptor");
693
694 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
695 supportedTypes,
696 "AdditionQueueDescriptor");
697
telsoa014fcda012018-03-09 14:13:49 +0000698 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
699 workloadInfo.m_InputTensorInfos[1],
700 workloadInfo.m_OutputTensorInfos[0],
701 "AdditionQueueDescriptor",
702 "first input",
703 "second input");
telsoa014fcda012018-03-09 14:13:49 +0000704}
705
706//---------------------------------------------------------------
707void MultiplicationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
708{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100709 ValidateNumInputs(workloadInfo, "MultiplicationQueueDescriptor", 2);
710 ValidateNumOutputs(workloadInfo, "MultiplicationQueueDescriptor", 1);
surmeh01bceff2f2018-03-29 16:29:27 +0100711
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100712 std::vector<DataType> supportedTypes = {
713 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +0100714 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +0100715 DataType::QuantisedSymm16,
716 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100717 };
718
719 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
720 supportedTypes,
721 "MultiplicationQueueDescriptor");
722
723 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
724 supportedTypes,
725 "MultiplicationQueueDescriptor");
726
727 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
728 supportedTypes,
729 "MultiplicationQueueDescriptor");
730
surmeh01bceff2f2018-03-29 16:29:27 +0100731 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
732 workloadInfo.m_InputTensorInfos[1],
733 workloadInfo.m_OutputTensorInfos[0],
734 "MultiplicationQueueDescriptor",
735 "first input",
736 "second input");
telsoa014fcda012018-03-09 14:13:49 +0000737}
738
739void BatchNormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
740{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100741 ValidateNumInputs(workloadInfo, "BatchNormalizationQueueDescriptor", 1);
742 ValidateNumOutputs(workloadInfo, "BatchNormalizationQueueDescriptor", 1);
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100743
744 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
745 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
746
747 std::vector<DataType> supportedTypes =
748 {
749 DataType::Float16,
750 DataType::Float32,
Matteo Martincighf5507132019-06-04 10:59:47 +0100751 DataType::QuantisedAsymm8,
752 DataType::QuantisedSymm16
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100753 };
754
755 ValidateDataTypes(input, supportedTypes, "BatchNormalizationQueueDescriptor");
756 ValidateDataTypes(output, supportedTypes, "BatchNormalizationQueueDescriptor");
757
758 ValidateDataTypes(output, { input.GetDataType() }, "BatchNormalizationQueueDescriptor");
759
760 ValidateTensorQuantizationSpace(input, output, "BatchNormalizationQueueDescriptor", "input", "output");
761
telsoa014fcda012018-03-09 14:13:49 +0000762 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
763 workloadInfo.m_OutputTensorInfos[0],
764 "BatchNormalizationQueueDescriptor",
765 "input",
766 "output");
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100767
768 ValidatePointer(m_Mean, "BatchNormalizationQueueDescriptor", "mean");
telsoa014fcda012018-03-09 14:13:49 +0000769 ValidatePointer(m_Variance, "BatchNormalizationQueueDescriptor", "variance");
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100770 ValidatePointer(m_Beta, "BatchNormalizationQueueDescriptor", "beta");
771 ValidatePointer(m_Gamma, "BatchNormalizationQueueDescriptor", "gamma");
telsoa014fcda012018-03-09 14:13:49 +0000772
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100773 const TensorInfo& mean = m_Mean->GetTensorInfo();
774 const TensorInfo& variance = m_Variance->GetTensorInfo();
775 const TensorInfo& beta = m_Beta->GetTensorInfo();
776 const TensorInfo& gamma = m_Gamma->GetTensorInfo();
telsoa014fcda012018-03-09 14:13:49 +0000777
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100778 ValidateTensorNumDimensions(mean, "BatchNormalizationQueueDescriptor", 1, "mean");
779 ValidateTensorNumDimensions(variance, "BatchNormalizationQueueDescriptor", 1, "variance");
780 ValidateTensorNumDimensions(beta, "BatchNormalizationQueueDescriptor", 1, "beta");
781 ValidateTensorNumDimensions(gamma, "BatchNormalizationQueueDescriptor", 1, "gamma");
telsoa014fcda012018-03-09 14:13:49 +0000782
Matteo Martincigh3122bd52019-06-03 16:54:25 +0100783 ValidateTensorShapesMatch(mean, variance, "BatchNormalizationQueueDescriptor", "mean", "variance");
784 ValidateTensorShapesMatch(mean, beta, "BatchNormalizationQueueDescriptor", "mean", "beta");
785 ValidateTensorShapesMatch(mean, gamma, "BatchNormalizationQueueDescriptor", "mean", "gamma");
telsoa014fcda012018-03-09 14:13:49 +0000786}
787
788void Convolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
789{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100790 ValidateNumInputs(workloadInfo, "Convolution2dQueueDescriptor", 1);
791 ValidateNumOutputs(workloadInfo, "Convolution2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000792
793 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "Convolution2dQueueDescriptor", 4, "input");
794 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "Convolution2dQueueDescriptor", 4, "output");
795
796 ValidatePointer(m_Weight, "Convolution2dQueueDescriptor", "weight");
797 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "Convolution2dQueueDescriptor", 4, "weight");
798 ValidateTensorDataType(m_Weight->GetTensorInfo(), workloadInfo.m_InputTensorInfos[0].GetDataType(),
799 "Convolution2dQueueDescriptor", "weight");
800 if (m_Parameters.m_BiasEnabled)
801 {
802 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "Convolution2dQueueDescriptor", 1, "bias");
803 ValidateTensorDataType(m_Bias->GetTensorInfo(),
804 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
805 "Convolution2dQueueDescriptor", "bias");
806 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
807 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "Convolution2dQueueDescriptor");
808 }
809
810 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
811 workloadInfo.m_OutputTensorInfos[0], "Convolution2dQueueDescriptor", "input", "weights", "output");
812}
813
814void DepthwiseConvolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
815{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100816 ValidateNumInputs(workloadInfo, "DepthwiseConvolution2dQueueDescriptor", 1);
817 ValidateNumOutputs(workloadInfo, "DepthwiseConvolution2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000818
819 ValidateTensorNumDimensions(
820 workloadInfo.m_InputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", 4, "input");
821 ValidateTensorNumDimensions(
822 workloadInfo.m_OutputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", 4, "output");
823
824 ValidatePointer(m_Weight, "DepthwiseConvolution2dQueueDescriptor", "weight");
825 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 4, "weight");
826
Bruno Goncalves22972f02019-04-26 21:03:24 -0300827 if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 )
828 {
829 throw InvalidArgumentException(
830 boost::str(boost::format("DepthwiseConvolution2dQueueDescriptor: dilationX (provided %1%) "
831 "and dilationY (provided %2%) cannot be smaller than 1.")
832 % m_Parameters.m_DilationX % m_Parameters.m_DilationX));
833 }
834
Nikhil Rajcec6b652018-10-12 13:51:57 +0100835 const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
836
Matteo Martincigh747ef822018-12-18 09:26:39 +0000837 // Expected weight shape: [ M, I, H, W ] - This shape does NOT depend on the data layout
838 // inputChannels * channelMultiplier should be equal to outputChannels.
telsoa014fcda012018-03-09 14:13:49 +0000839 const unsigned int numWeightChannelMultiplier = m_Weight->GetTensorInfo().GetShape()[0];
Matteo Martincigh747ef822018-12-18 09:26:39 +0000840 const unsigned int numWeightInputChannels = m_Weight->GetTensorInfo().GetShape()[1];
Nikhil Rajcec6b652018-10-12 13:51:57 +0100841 const unsigned int numWeightOutputChannels = workloadInfo.m_OutputTensorInfos[0].GetShape()[channelIndex];
telsoa014fcda012018-03-09 14:13:49 +0000842 if (numWeightChannelMultiplier * numWeightInputChannels != numWeightOutputChannels)
843 {
844 throw InvalidArgumentException(
845 boost::str(boost::format("DepthwiseConvolution2dQueueDescriptor: output_channels (provided %1%) should be "
846 "equal to input_channels (provided %2%) multiplied by channel_multiplier "
847 "(provided %3%).")
848 % numWeightOutputChannels % numWeightInputChannels % numWeightChannelMultiplier));
849 }
850
851 if (m_Parameters.m_BiasEnabled)
852 {
853 ValidatePointer(m_Bias, "DepthwiseConvolution2dQueueDescriptor", "bias");
854 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 1, "bias");
855 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
856 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor");
857
858 ValidateTensorDataType(m_Bias->GetTensorInfo(),
859 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
860 "DepthwiseConvolution2dQueueDescriptor", "bias");
861 }
862
863 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
864 workloadInfo.m_OutputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", "input", "weights", "output");
Ruomei Yan88d44b82019-05-23 14:29:06 +0100865
866 // Check the supported data types
867 std::vector<DataType> supportedTypes = {
868 DataType::Float32,
869 DataType::QuantisedAsymm8,
870 DataType::QuantisedSymm16,
871 DataType::Float16
872 };
873
874 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
875 supportedTypes,
876 "DepthwiseConvolution2dQueueDescriptor");
877
878 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
879 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
880 "DepthwiseConvolution2dQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000881}
882
883void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
884{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100885 ValidateNumInputs(workloadInfo, "PermuteQueueDescriptor", 1);
886 ValidateNumOutputs(workloadInfo, "PermuteQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000887
888 const PermutationVector& mapping = m_Parameters.m_DimMappings;
889
890 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
891 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
892
893 ValidateTensorNumDimensions(input, "PermuteQueueDescriptor", mapping.GetSize(), "input");
894 ValidateTensorNumDimensions(output, "PermuteQueueDescriptor", mapping.GetSize(), "output");
895
896 for (unsigned int i = 0; i < mapping.GetSize(); ++i)
897 {
898 if (input.GetShape()[i] != output.GetShape()[mapping[i]])
899 {
900 throw InvalidArgumentException("PermuteQueueDescriptor: src dimension " + to_string(i) +
901 " (=" + to_string(input.GetShape()[i]) + ") " +
902 "must match dst dimension " + to_string(mapping[i]) +
903 " (=" + to_string(output.GetShape()[mapping[i]]) + ")");
904 }
905 }
906}
907
908void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
909{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100910 ValidateNumInputs(workloadInfo, "Pooling2dQueueDescriptor", 1);
911 ValidateNumOutputs(workloadInfo, "Pooling2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000912
913 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "Pooling2dQueueDescriptor", 4, "input");
914 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "Pooling2dQueueDescriptor", 4, "output");
Teresa Charlina3b20472019-06-06 11:12:32 +0100915
916 std::vector<DataType> supportedTypes =
917 {
918 DataType::Float32,
919 DataType::Float16,
Teresa Charlin0434df62019-06-06 13:40:35 +0100920 DataType::QuantisedAsymm8,
921 DataType::QuantisedSymm16
Teresa Charlina3b20472019-06-06 11:12:32 +0100922 };
923
924 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
925 supportedTypes,
926 "Pooling2dQueueDescriptor");
927
928 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
929 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
930 "Pooling2dQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000931}
932
933void ResizeBilinearQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
934{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100935 ValidateNumInputs(workloadInfo, "ResizeBilinearQueueDescriptor", 1);
936 ValidateNumOutputs(workloadInfo, "ResizeBilinearQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000937
938 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "ResizeBilinearQueueDescriptor", 4, "input");
939 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "ResizeBilinearQueueDescriptor", 4, "output");
940
Ellen Norris-Thompson3cb85f32019-06-17 11:32:49 +0100941 std::vector<DataType> supportedTypes =
Teresa Charlin970f43b2019-07-01 13:51:07 +0100942 {
943 DataType::Float16,
944 DataType::Float32,
945 DataType::QuantisedAsymm8,
946 DataType::QuantisedSymm16
947 };
Ellen Norris-Thompson3cb85f32019-06-17 11:32:49 +0100948
949 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
950 supportedTypes,
951 "ResizeBilinearQueueDescriptor");
952
953 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
954 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
955 "ResizeBilinearQueueDescriptor");
956
telsoa01c577f2c2018-08-31 09:22:23 +0100957 // Resizes bilinear only changes width and height: batch and channel count must match.
Teresa Charlin970f43b2019-07-01 13:51:07 +0100958 const unsigned int inputBatchSize = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
959 const unsigned int outputBatchSize = workloadInfo.m_OutputTensorInfos[0].GetShape()[0];
960 if (inputBatchSize != outputBatchSize)
telsoa014fcda012018-03-09 14:13:49 +0000961 {
Teresa Charlin970f43b2019-07-01 13:51:07 +0100962 throw InvalidArgumentException(
963 boost::str(boost::format("ResizeBilinearQueueDescriptor: Input batch size (%1%) "
964 "does not match output batch size (%2%)") % inputBatchSize % outputBatchSize));
telsoa014fcda012018-03-09 14:13:49 +0000965 }
966
Teresa Charlin970f43b2019-07-01 13:51:07 +0100967 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
968 const unsigned int inputChannelCount =
969 workloadInfo.m_InputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
970 const unsigned int outputChannelCount =
971 workloadInfo.m_OutputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
972 if (inputChannelCount != outputChannelCount)
telsoa014fcda012018-03-09 14:13:49 +0000973 {
Teresa Charlin970f43b2019-07-01 13:51:07 +0100974 throw InvalidArgumentException(
975 boost::str(boost::format("ResizeBilinearQueueDescriptor: Input channel count (%1%) "
976 "does not match output channel count (%2%)") % inputChannelCount % outputChannelCount));
977 }
978}
979
980void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
981{
982 ValidateNumInputs(workloadInfo, "ResizeQueueDescriptor", 1);
983 ValidateNumOutputs(workloadInfo, "ResizeQueueDescriptor", 1);
984
985 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "ResizeQueueDescriptor", 4, "input");
986 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "ResizeQueueDescriptor", 4, "output");
987
988 std::vector<DataType> supportedTypes =
989 {
990 DataType::Float16,
991 DataType::Float32,
992 DataType::QuantisedAsymm8,
993 DataType::QuantisedSymm16
994 };
995
996 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
997 supportedTypes,
998 "ResizeQueueDescriptor");
999
1000 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1001 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
1002 "ResizeQueueDescriptor");
1003
1004 // Resizes only changes width and height: batch and channel count must match.
1005 const unsigned int inputBatchSize = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
1006 const unsigned int outputBatchSize = workloadInfo.m_OutputTensorInfos[0].GetShape()[0];
1007 if (inputBatchSize != outputBatchSize)
1008 {
1009 throw InvalidArgumentException(
1010 boost::str(boost::format("ResizeQueueDescriptor: Input batch size (%1%) "
1011 "does not match output batch size (%2%)") % inputBatchSize % outputBatchSize));
1012 }
1013
1014 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1015 const unsigned int inputChannelCount =
Matthew Bentham8800c002018-11-19 13:19:28 +00001016 workloadInfo.m_InputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
Teresa Charlin970f43b2019-07-01 13:51:07 +01001017 const unsigned int outputChannelCount =
Matthew Bentham8800c002018-11-19 13:19:28 +00001018 workloadInfo.m_OutputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
Teresa Charlin970f43b2019-07-01 13:51:07 +01001019 if (inputChannelCount != outputChannelCount)
1020 {
1021 throw InvalidArgumentException(
1022 boost::str(boost::format("ResizeQueueDescriptor: Input channel count (%1%) "
1023 "does not match output channel count (%2%)") % inputChannelCount % outputChannelCount));
telsoa014fcda012018-03-09 14:13:49 +00001024 }
1025}
1026
1027void FakeQuantizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1028{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001029 ValidateNumInputs(workloadInfo, "FakeQuantizationQueueDescriptor", 1);
1030 ValidateNumOutputs(workloadInfo, "FakeQuantizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +00001031
1032 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "FakeQuantizationQueueDescriptor", 2, "input");
1033 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "FakeQuantizationQueueDescriptor", 2, "output");
1034 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1035 workloadInfo.m_OutputTensorInfos[0],
1036 "FakeQuantizationQueueDescriptor",
1037 "input",
1038 "output");
1039 if (m_Parameters.m_Min > m_Parameters.m_Max)
1040 {
1041 throw InvalidArgumentException("FakeQuantizationQueueDescriptor: min cannot be greater than max");
1042 }
1043
1044}
1045
1046void L2NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1047{
Ferran Balaguerd73d14f2019-06-10 10:29:54 +01001048 const std::string& descriptorName = "L2NormalizationQueueDescriptor";
telsoa014fcda012018-03-09 14:13:49 +00001049
Ferran Balaguerd73d14f2019-06-10 10:29:54 +01001050 ValidateNumInputs(workloadInfo, descriptorName, 1);
1051 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1052
1053 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], descriptorName, 4, "input");
1054 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], descriptorName, 4, "output");
telsoa014fcda012018-03-09 14:13:49 +00001055 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1056 workloadInfo.m_OutputTensorInfos[0],
Ferran Balaguerd73d14f2019-06-10 10:29:54 +01001057 descriptorName,
telsoa014fcda012018-03-09 14:13:49 +00001058 "input",
1059 "output");
Ferran Balaguerd73d14f2019-06-10 10:29:54 +01001060
1061 // Check the supported data types
1062 std::vector<DataType> supportedTypes =
1063 {
1064 DataType::Float32,
1065 DataType::Float16,
1066 DataType::QuantisedAsymm8,
1067 DataType::QuantisedSymm16
1068 };
1069
1070 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
1071 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, descriptorName);
1072 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1073 {workloadInfo.m_InputTensorInfos[0].GetDataType()}, descriptorName);
telsoa014fcda012018-03-09 14:13:49 +00001074}
1075
1076void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1077{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001078 ValidateNumInputs(workloadInfo, "ConstantQueueDescriptor", 0);
1079 ValidateNumOutputs(workloadInfo, "ConstantQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +00001080
1081 if (!m_LayerOutput)
1082 {
1083 throw InvalidArgumentException("ConstantQueueDescriptor: No const input specified");
1084 }
1085
1086 ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(),
1087 workloadInfo.m_OutputTensorInfos[0],
1088 "ConstantQueueDescriptor",
1089 "constant",
1090 "output");
Nina Drozd58ef2c62019-05-16 12:09:18 +01001091
1092 // Check the supported data types
1093 std::vector<DataType> supportedTypes =
Nina Drozd2f2778f2019-05-27 10:37:05 +01001094 {
1095 DataType::Float32,
1096 DataType::Float16,
1097 DataType::Signed32,
1098 DataType::QuantisedAsymm8,
1099 DataType::QuantisedSymm16
1100 };
Nina Drozd58ef2c62019-05-16 12:09:18 +01001101
1102 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, "ConstantQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +00001103}
1104
1105void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1106{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001107 ValidateNumInputs(workloadInfo, "ReshapeQueueDescriptor", 1);
1108 ValidateNumOutputs(workloadInfo, "ReshapeQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +00001109
1110 if (workloadInfo.m_InputTensorInfos[0].GetNumElements() != workloadInfo.m_OutputTensorInfos[0].GetNumElements())
1111 {
1112 throw InvalidArgumentException("ReshapeQueueDescriptor: Input tensor has " +
1113 to_string(workloadInfo.m_InputTensorInfos[0].GetNumElements()) + " but output tensor has " +
1114 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
1115 }
Nina Drozd2f2778f2019-05-27 10:37:05 +01001116
1117 // Check the supported data types
1118 std::vector<DataType> supportedTypes =
1119 {
1120 DataType::Float32,
1121 DataType::Float16,
Nina Drozd8ed4b8c2019-05-29 10:41:04 +01001122 DataType::QuantisedAsymm8,
1123 DataType::QuantisedSymm16
Nina Drozd2f2778f2019-05-27 10:37:05 +01001124 };
1125
1126 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, "ReshapeQueueDescriptor");
1127 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, "ReshapeQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +00001128}
1129
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001130void SpaceToBatchNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1131{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001132 ValidateNumInputs(workloadInfo, "SpaceToBatchNdQueueDescriptor", 1);
1133 ValidateNumOutputs(workloadInfo, "SpaceToBatchNdQueueDescriptor", 1);
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001134
1135 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "SpaceToBatchNdQueueDescriptor", 4, "input");
1136 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "SpaceToBatchNdQueueDescriptor", 4, "output");
1137
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001138 if (m_Parameters.m_BlockShape.size() != 2)
1139 {
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001140 throw InvalidArgumentException("Block Shape must contain 2 spatial dimensions");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001141 }
1142
1143 if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
1144 {
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001145 throw InvalidArgumentException("Pad List must contain the same number of dimensions as Block Shape.");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001146 }
1147
1148 const TensorShape inputShape = workloadInfo.m_InputTensorInfos[0].GetShape();
1149
1150 std::pair<unsigned int, unsigned int> heightPad = m_Parameters.m_PadList[0];
1151 std::pair<unsigned int, unsigned int> widthPad = m_Parameters.m_PadList[1];
1152
Matthew Bentham8800c002018-11-19 13:19:28 +00001153 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1154 unsigned int inputHeight = inputShape[dimensionIndices.GetHeightIndex()]
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001155 + heightPad.first + heightPad.second;
1156
Matthew Bentham8800c002018-11-19 13:19:28 +00001157 unsigned int inputWidth = inputShape[dimensionIndices.GetWidthIndex()]
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001158 + widthPad.first + widthPad.second;
1159
1160 unsigned int numInputElements = inputShape[0] * inputHeight * inputWidth
Matthew Bentham8800c002018-11-19 13:19:28 +00001161 * inputShape[dimensionIndices.GetChannelsIndex()];
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +00001162
1163 if (workloadInfo.m_OutputTensorInfos[0].GetNumElements() != numInputElements)
1164 {
1165 throw InvalidArgumentException("SpaceToBatchNdQueueDescriptor: Input tensor has " +
1166 to_string(numInputElements) + " after padding but output tensor has " +
1167 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
1168 }
1169
1170 if (inputHeight % m_Parameters.m_BlockShape[0] != 0 || inputWidth % m_Parameters.m_BlockShape[1] != 0)
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001171 {
1172 throw InvalidArgumentException(
1173 "Input shape after padding must be divisible by Block Shape in all spatial dimensions");
1174 }
nikraj01120522a2019-05-31 11:33:07 +01001175
1176 std::vector<DataType> supportedTypes =
1177 {
1178 DataType::Float16,
1179 DataType::Float32,
1180 DataType::QuantisedAsymm8,
1181 DataType::QuantisedSymm16
1182 };
1183
1184 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1185 supportedTypes,
1186 "SpaceToBatchNdQueueDescriptor");
1187
1188 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1189 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
1190 "SpaceToBatchNdQueueDescriptor");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001191}
1192
Keith Davisa57eccb2019-06-14 17:33:22 +01001193void SpaceToDepthQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1194{
1195 ValidateNumInputs(workloadInfo, "SpaceToDepthQueueDescriptor", 1);
1196 ValidateNumOutputs(workloadInfo, "SpaceToDepthQueueDescriptor", 1);
1197
1198 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0],
1199 "SpaceToDepthQueueDescriptor", 4, "input");
1200 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0],
1201 "SpaceToDepthQueueDescriptor", 4, "output");
1202
1203 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1204
1205 std::vector<DataType> supportedTypes =
1206 {
1207 DataType::Float32,
1208 DataType::Float16,
James Conroyd2aa85e2019-07-01 17:12:40 +01001209 DataType::QuantisedAsymm8,
1210 DataType::QuantisedSymm16
Keith Davisa57eccb2019-06-14 17:33:22 +01001211 };
1212
1213 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1214 supportedTypes,
1215 "SpaceToDepthQueueDescriptor");
1216 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1217 supportedTypes,
1218 "SpaceToDepthQueueDescriptor");
1219
1220 const TensorShape inputShape = workloadInfo.m_InputTensorInfos[0].GetShape();
1221
1222 unsigned int numInputElements = inputShape[0]
1223 * inputShape[dimensionIndices.GetWidthIndex()]
1224 * inputShape[dimensionIndices.GetHeightIndex()]
1225 * inputShape[dimensionIndices.GetChannelsIndex()];
1226
1227 if (workloadInfo.m_OutputTensorInfos[0].GetNumElements() != numInputElements)
1228 {
1229 throw InvalidArgumentException("SpaceToDepthQueueDescriptor: Input tensor has " +
1230 to_string(numInputElements) + " but output tensor has " +
1231 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
1232 }
1233
1234 if (inputShape[dimensionIndices.GetHeightIndex()] % m_Parameters.m_BlockSize != 0 ||
1235 inputShape[dimensionIndices.GetWidthIndex()] % m_Parameters.m_BlockSize != 0)
1236 {
1237 throw InvalidArgumentException(
1238 "Input shape must be divisible by block size in all spatial dimensions");
1239 }
1240}
1241
telsoa014fcda012018-03-09 14:13:49 +00001242void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1243{
James Conroy83735b12019-05-30 16:36:59 +01001244 const std::string floorQueueDescString = "FloorQueueDescriptor";
1245
1246 ValidateNumInputs(workloadInfo, floorQueueDescString, 1);
1247 ValidateNumOutputs(workloadInfo, floorQueueDescString, 1);
1248
1249 std::vector<DataType> supportedTypes =
1250 {
James Conroyb40d7102019-06-04 12:32:09 +01001251 DataType::Float32,
1252 DataType::QuantisedSymm16
James Conroy83735b12019-05-30 16:36:59 +01001253 };
1254
1255 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, floorQueueDescString);
1256 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, floorQueueDescString);
telsoa014fcda012018-03-09 14:13:49 +00001257
1258 if (workloadInfo.m_InputTensorInfos[0] != workloadInfo.m_OutputTensorInfos[0])
1259 {
James Conroy83735b12019-05-30 16:36:59 +01001260 throw InvalidArgumentException(floorQueueDescString + ": Input and output tensor infos do not match.");
telsoa014fcda012018-03-09 14:13:49 +00001261 }
1262}
1263
telsoa01c577f2c2018-08-31 09:22:23 +01001264void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1265{
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001266 std::vector<DataType> supportedTypes = {
Conor Kennedyb9971c92019-05-07 07:14:23 +01001267 DataType::Float16,
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001268 DataType::Float32,
Conor Kennedyb9971c92019-05-07 07:14:23 +01001269 DataType::QuantisedSymm16
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001270 };
Jan Eilers38e05bd2019-06-26 13:10:09 +01001271 // ported from android/ml/nn/common/operations/LSTM.cpp CheckInputTensorDimensions()
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001272
Jan Eilers38e05bd2019-06-26 13:10:09 +01001273 // check for supported type of one input and match them with all the other input and output
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001274 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1275 supportedTypes,
1276 "LstmQueueDescriptor");
Jan Eilers38e05bd2019-06-26 13:10:09 +01001277 // type matches all other inputs
1278 for (uint32_t i = 1; i < workloadInfo.m_InputTensorInfos.size(); ++i)
1279 {
1280 ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1281 workloadInfo.m_InputTensorInfos[i],
1282 "LstmQueueDescriptor",
1283 "InputTensor[0]",
1284 "InputTensor[" + std::to_string(i) + "]");
1285 }
1286 // type matches all other outputs
1287 for (uint32_t i = 0; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
1288 {
1289 ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1290 workloadInfo.m_OutputTensorInfos[i],
1291 "LstmQueueDescriptor",
1292 "InputTensor[0]",
1293 "OutputTensor[" + std::to_string(i) + "]");
1294 }
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +01001295
Jan Eilers38e05bd2019-06-26 13:10:09 +01001296 // TODO: check clipping parameter is valid
1297
1298 // Inferring batch size, number of outputs and number of cells from the inputs.
1299 // TODO: figure out if there is a way to make sure the specific inputs are at that index of workloadInfo
1300 const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[1];
1301 const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
1302 ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
1303 const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
1304 ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
1305 const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
1306
1307 // check dimensions of all inputs and outputs
1308 if (workloadInfo.m_InputTensorInfos.size() != 3)
1309 {
1310 throw InvalidArgumentException("Invalid number of inputs.");
1311 }
1312 if (workloadInfo.m_OutputTensorInfos.size() != 4)
1313 {
1314 throw InvalidArgumentException("Invalid number of outputs.");
1315 }
1316 // input tensor
1317 ValidateTensorNumDimNumElem( workloadInfo.m_InputTensorInfos[0], 2, (n_batch * n_input),
1318 "LstmQueueDescriptor input[0]");
1319 // outputStateInTensor
1320 ValidateTensorNumDimNumElem( workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
1321 "LstmQueueDescriptor input[1]");
1322 // outputStateInTensor
1323 ValidateTensorNumDimNumElem( workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
1324 "LstmQueueDescriptor input[2]");
1325 // scratchBufferTensor
1326 unsigned int scratchBufferSize = m_Parameters.m_CifgEnabled ? n_cell * 3 : n_cell * 4;
1327 ValidateTensorNumDimNumElem( workloadInfo.m_OutputTensorInfos[0], 2, (n_batch * scratchBufferSize),
1328 "LstmQueueDescriptor output[0]");
1329 // outputStateOutTensor
1330 ValidateTensorNumDimNumElem( workloadInfo.m_OutputTensorInfos[1], 2, (n_batch * n_output),
1331 "LstmQueueDescriptor output[1]");
1332 // cellStateOutTensor
1333 ValidateTensorNumDimNumElem( workloadInfo.m_OutputTensorInfos[2], 2, (n_batch * n_cell),
1334 "LstmQueueDescriptor output[2]");
1335 // outputTensor
1336 ValidateTensorNumDimNumElem( workloadInfo.m_OutputTensorInfos[3], 2, (n_batch * n_output),
1337 "LstmQueueDescriptor output[3]");
1338
1339
1340 // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
1341 if ( m_InputToInputWeights )
1342 {
1343 ValidateTensorNumDimNumElem(m_InputToInputWeights->GetTensorInfo(), 2,
1344 (n_cell * n_input), "InputLayerNormWeights");
1345 }
1346
1347 ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
1348 ValidateTensorNumDimNumElem(m_InputToForgetWeights->GetTensorInfo(), 2,
1349 (n_cell * n_input), "InputToForgetWeights");
1350
1351 ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
1352 ValidateTensorNumDimNumElem(m_InputToCellWeights->GetTensorInfo(), 2,
1353 (n_cell * n_input), "InputToCellWeights");
1354
1355 if ( m_RecurrentToInputWeights )
1356 {
1357 ValidateTensorNumDimNumElem(m_RecurrentToInputWeights->GetTensorInfo(), 2,
1358 (n_cell * n_output), "RecurrentToInputWeights");
1359 }
1360
1361 ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
1362 ValidateTensorNumDimNumElem(m_RecurrentToForgetWeights->GetTensorInfo(), 2,
1363 (n_cell * n_output), "RecurrentToForgetWeights");
1364
1365 ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
1366 ValidateTensorNumDimNumElem(m_RecurrentToCellWeights->GetTensorInfo(), 2,
1367 (n_cell * n_output), "RecurrentToCellWeights");
1368
1369 // Make sure the input-gate's parameters are either both present (regular
1370 // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
1371 bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
1372 !m_Parameters.m_CifgEnabled) ||
1373 (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
1374 m_Parameters.m_CifgEnabled));
1375 if (!cifg_weights_all_or_none)
1376 {
1377 throw InvalidArgumentException("Input-Gate's parameters InputToInputWeights and RecurrentToInputWeights must "
1378 "either both be present (regular LSTM) or both not present (CIFG-LSTM). In "
1379 "addition CifgEnable must be set accordingly");
1380 }
1381
1382 if ( m_CellToInputWeights )
1383 {
1384 ValidateTensorNumDimNumElem(m_CellToInputWeights->GetTensorInfo(), 1,
1385 n_cell, "CellToInputWeights");
1386 }
1387 if ( m_CellToForgetWeights )
1388 {
1389 ValidateTensorNumDimNumElem(m_CellToForgetWeights->GetTensorInfo(), 1,
1390 n_cell, "CellToForgetWeights");
1391 }
1392 if ( m_CellToOutputWeights )
1393 {
1394 ValidateTensorNumDimNumElem(m_CellToOutputWeights->GetTensorInfo(), 1,
1395 n_cell, "CellToOutputWeights");
1396 }
1397
1398 // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
1399 bool peephole_weights_all_or_none =
1400 (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
1401 && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
1402 || ( !m_CellToInputWeights && !m_CellToForgetWeights
1403 && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
1404 if (!peephole_weights_all_or_none)
1405 {
1406 throw InvalidArgumentException("Invalid combination of peephole parameters");
1407 }
1408
1409 // Make sure the input gate bias is present only when not a CIFG-LSTM.
1410 if (m_Parameters.m_CifgEnabled)
1411 {
1412 if (m_InputGateBias)
1413 {
1414 throw InvalidArgumentException("InputGateBias is present and CIFG-LSTM is enabled");
1415 }
1416 }
1417 else
1418 {
1419 if (!m_InputGateBias)
1420 {
1421 throw InvalidArgumentException("If CIFG-LSTM is disabled InputGateBias must be present.");
1422 }
1423 ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1,
1424 n_cell, "InputGateBias");
1425 }
1426
1427 ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
1428 ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
1429
1430 ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
1431 ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
1432
1433 ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
1434 ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
1435
1436 if (m_ProjectionWeights)
1437 {
1438 ValidateTensorNumDimNumElem(m_ProjectionWeights->GetTensorInfo(), 2,
1439 (n_cell * n_output), "ProjectionWeights");
1440 }
1441 if (m_ProjectionBias)
1442 {
1443 ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
1444 }
1445
1446 // Making sure the projection tensors are consistent:
1447 // 1) If projection weight is not present, then projection bias should not be
1448 // present.
1449 // 2) If projection weight is present, then projection bias is optional.
1450 bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
1451 !m_Parameters.m_ProjectionEnabled)
1452 || (m_ProjectionWeights && !m_ProjectionBias &&
1453 m_Parameters.m_ProjectionEnabled)
1454 || (m_ProjectionWeights && m_ProjectionBias &&
1455 m_Parameters.m_ProjectionEnabled));
1456 if (!projecton_tensors_consistent)
1457 {
1458 throw InvalidArgumentException("Projection tensors are inconsistent.");
1459 }
1460
1461 // The four layer normalization weights either all have values or none of them have values. Additionally, if
1462 // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
1463 // either all have values or none of them have values. Layer normalization is used when the values of all the
1464 // layer normalization weights are present
1465 if (m_InputLayerNormWeights)
1466 {
1467 ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
1468 }
1469 if (m_ForgetLayerNormWeights)
1470 {
1471 ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
1472 }
1473 if (m_CellLayerNormWeights)
1474 {
1475 ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
1476 }
1477 if (m_OutputLayerNormWeights)
1478 {
1479 ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
1480 }
1481
1482
1483 if (m_Parameters.m_LayerNormEnabled)
1484 {
1485 if (!m_Parameters.m_CifgEnabled)
1486 {
1487 if (!m_InputLayerNormWeights)
1488 {
1489 throw InvalidArgumentException("Layer normalisation is enabled and CIFG-LSTM is disabled but "
1490 "InputLayerNormWeights are not present");
1491 }
1492 ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(),
1493 1, n_cell, "InputLayerNormWeights");
1494 }
1495 else if (m_InputLayerNormWeights)
1496 {
1497 throw InvalidArgumentException("InputLayerNormWeights are present while CIFG is enabled");
1498 }
1499
1500 ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
1501 "ForgetLayerNormWeights");
1502 ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
1503
1504 ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
1505 "OutputLayerNormWeights");
1506 ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
1507
1508 ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
1509 "CellLayerNormWeights");
1510 ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
1511 }
1512 else if (m_InputLayerNormWeights || m_ForgetLayerNormWeights || m_OutputLayerNormWeights || m_CellLayerNormWeights)
1513 {
1514 throw InvalidArgumentException("Layer normalisation is disabled but one or more layer normalisation weights "
1515 "are present.");
1516 }
telsoa01c577f2c2018-08-31 09:22:23 +01001517}
1518
1519void ConvertFp32ToFp16QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1520{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001521 ValidateNumInputs(workloadInfo, "ConvertFp32ToFp16QueueDescriptor", 1);
1522 ValidateNumOutputs(workloadInfo, "ConvertFp32ToFp16QueueDescriptor", 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001523
1524 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float32)
1525 {
1526 throw InvalidArgumentException("ConvertFp32ToFp16QueueDescriptor: Input tensor type must be Float32.");
1527 }
1528
1529 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float16)
1530 {
1531 throw InvalidArgumentException("ConvertFp32ToFp16QueueDescriptor: Output tensor type must be Float16.");
1532 }
1533
1534 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1535 workloadInfo.m_OutputTensorInfos[0],
1536 "ConvertFp32ToFp16QueueDescriptor",
1537 "input",
1538 "output");
1539}
1540
1541void ConvertFp16ToFp32QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1542{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001543 ValidateNumInputs(workloadInfo, "ConvertFp16ToFp32QueueDescriptor", 1);
1544 ValidateNumOutputs(workloadInfo, "ConvertFp16ToFp32QueueDescriptor", 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001545
1546 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float16)
1547 {
1548 throw InvalidArgumentException("ConvertFp16ToFp32QueueDescriptor: Input tensor type must be Float16.");
1549 }
1550 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float32)
1551 {
1552 throw InvalidArgumentException("ConvertFp16ToFp32QueueDescriptor: Output tensor type must be Float32.");
1553 }
1554
1555 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1556 workloadInfo.m_OutputTensorInfos[0],
1557 "ConvertFp16ToFp32QueueDescriptor",
1558 "input",
1559 "output");
1560}
1561
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001562void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1563{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001564 ValidateNumInputs(workloadInfo, "DivisionQueueDescriptor", 2);
1565 ValidateNumOutputs(workloadInfo, "DivisionQueueDescriptor", 1);
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001566
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001567 std::vector<DataType> supportedTypes = {
1568 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001569 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +01001570 DataType::QuantisedSymm16,
1571 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001572 };
1573
1574 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1575 supportedTypes,
1576 "DivisionQueueDescriptor");
1577
1578 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1579 supportedTypes,
1580 "DivisionQueueDescriptor");
1581
1582 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1583 supportedTypes,
1584 "DivisionQueueDescriptor");
1585
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001586 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1587 workloadInfo.m_InputTensorInfos[1],
1588 workloadInfo.m_OutputTensorInfos[0],
1589 "DivisionQueueDescriptor",
1590 "first input",
1591 "second input");
1592}
1593
David Beckc2044fe2018-09-05 15:00:38 +01001594void SubtractionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1595{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001596 ValidateNumInputs(workloadInfo, "SubtractionQueueDescriptor", 2);
1597 ValidateNumOutputs(workloadInfo, "SubtractionQueueDescriptor", 1);
David Beckc2044fe2018-09-05 15:00:38 +01001598
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001599 std::vector<DataType> supportedTypes = {
1600 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001601 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +01001602 DataType::QuantisedSymm16,
1603 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001604 };
1605
1606 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1607 supportedTypes,
1608 "SubtractionQueueDescriptor");
1609
1610 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1611 supportedTypes,
1612 "SubtractionQueueDescriptor");
1613
1614 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1615 supportedTypes,
1616 "SubtractionQueueDescriptor");
1617
David Beckc2044fe2018-09-05 15:00:38 +01001618 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1619 workloadInfo.m_InputTensorInfos[1],
1620 workloadInfo.m_OutputTensorInfos[0],
1621 "SubtractionQueueDescriptor",
1622 "first input",
1623 "second input");
1624}
1625
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001626void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1627{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001628 ValidateNumInputs(workloadInfo, "MaximumQueueDescriptor", 2);
1629 ValidateNumOutputs(workloadInfo, "MaximumQueueDescriptor", 1);
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001630
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001631 std::vector<DataType> supportedTypes = {
1632 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001633 DataType::QuantisedAsymm8,
1634 DataType::QuantisedSymm16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001635 };
1636
1637 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1638 supportedTypes,
1639 "MaximumQueueDescriptor");
1640
1641 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1642 supportedTypes,
1643 "MaximumQueueDescriptor");
1644
1645 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1646 supportedTypes,
1647 "MaximumQueueDescriptor");
1648
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001649 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1650 workloadInfo.m_InputTensorInfos[1],
1651 workloadInfo.m_OutputTensorInfos[0],
1652 "MaximumQueueDescriptor",
1653 "first input",
1654 "second input");
1655}
1656
narpra01a6bf9122018-09-10 09:50:09 +01001657void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1658{
James Conroy4d1ff582019-06-10 17:06:39 +01001659 const std::string meanQueueDescString = "MeanQueueDescriptor";
1660
1661 ValidateNumInputs(workloadInfo, meanQueueDescString, 1);
1662 ValidateNumOutputs(workloadInfo, meanQueueDescString, 1);
1663
1664 std::vector<DataType> supportedTypes =
1665 {
1666 DataType::Float32,
1667 DataType::Float16,
1668 DataType::QuantisedAsymm8,
1669 DataType::QuantisedSymm16
1670 };
narpra01eb061912018-09-10 17:35:27 +01001671
1672 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
1673 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1674
James Conroy4d1ff582019-06-10 17:06:39 +01001675 // First check if input tensor data type is supported, then
1676 // check if this data type matches the output tensor data type
1677 ValidateDataTypes(input, supportedTypes, meanQueueDescString);
1678 ValidateTensorDataTypesMatch(input, output, meanQueueDescString, "input", "output");
1679
narpra0132b90462018-09-13 11:07:48 +01001680 if (m_Parameters.m_KeepDims)
narpra01eb061912018-09-10 17:35:27 +01001681 {
James Conroy4d1ff582019-06-10 17:06:39 +01001682 ValidateTensorNumDimensions(output, meanQueueDescString, input.GetNumDimensions(), "output");
narpra01eb061912018-09-10 17:35:27 +01001683 }
narpra0132b90462018-09-13 11:07:48 +01001684 else if (m_Parameters.m_Axis.empty())
narpra01eb061912018-09-10 17:35:27 +01001685 {
James Conroy4d1ff582019-06-10 17:06:39 +01001686 ValidateTensorNumDimensions(output, meanQueueDescString, 1, "output");
narpra01eb061912018-09-10 17:35:27 +01001687 }
1688 else
1689 {
narpra0132b90462018-09-13 11:07:48 +01001690 auto outputDim = input.GetNumDimensions() - boost::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
narpra01eb061912018-09-10 17:35:27 +01001691 ValidateTensorNumDimensions(output,
James Conroy4d1ff582019-06-10 17:06:39 +01001692 meanQueueDescString,
narpra01eb061912018-09-10 17:35:27 +01001693 outputDim > 0 ? outputDim : 1,
1694 "output");
1695 }
narpra01a6bf9122018-09-10 09:50:09 +01001696}
1697
jimfly012c9322a2018-09-19 10:59:49 +01001698void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1699{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001700 ValidateNumInputs(workloadInfo, "PadQueueDescriptor", 1);
1701 ValidateNumOutputs(workloadInfo, "PadQueueDescriptor", 1);
jimfly012c9322a2018-09-19 10:59:49 +01001702
1703 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
Nina Drozd661dfa72018-10-02 11:14:17 +01001704 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1705
jimfly012c9322a2018-09-19 10:59:49 +01001706 // input and output should have the same number of dimensions
1707 ValidateTensorNumDimensions(output, "PadQueueDescriptor", input.GetNumDimensions(), "output");
1708 // there should be entry in the pad list for each dimension in the input tensor
1709 if (m_Parameters.m_PadList.size() != input.GetNumDimensions()) {
1710 throw InvalidArgumentException("Pad List should contain the same number of entries as there"
1711 " are dimensions in the input tensor that is " +
1712 to_string(input.GetNumDimensions()) + " entries " +
1713 " not " + to_string(m_Parameters.m_PadList.size()) + " entries.");
1714 }
1715}
1716
Derek Lambertia9cca6a2019-03-25 15:41:58 +00001717void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1718{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001719 ValidateNumInputs(workloadInfo, "QuantizeQueueDescriptor", 1);
1720 ValidateNumOutputs(workloadInfo, "QuantizeQueueDescriptor", 1);
Derek Lambertia9cca6a2019-03-25 15:41:58 +00001721
1722
1723 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float32)
1724 {
1725 throw InvalidArgumentException("Quantize only accepts Float32 inputs.");
1726 }
1727
1728 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::QuantisedAsymm8 &&
1729 workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::QuantisedSymm16)
1730 {
1731 throw InvalidArgumentException("Output of quantized layer must be quantized type.");
1732 }
1733}
1734
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +00001735void BatchToSpaceNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1736{
Francis Murtaghd0dfe172019-06-25 10:57:10 +01001737 const std::string batchToSpaceNdQueueDescriptorStr = "BatchToSpaceNdQueueDescriptor";
1738
1739 ValidateNumInputs(workloadInfo, batchToSpaceNdQueueDescriptorStr, 1);
1740 ValidateNumOutputs(workloadInfo, batchToSpaceNdQueueDescriptorStr, 1);
1741
1742 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
1743 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1744
1745 std::vector<DataType> supportedTypes =
1746 {
1747 DataType::Float32,
1748 DataType::QuantisedAsymm8,
1749 DataType::QuantisedSymm16
1750 };
1751
1752 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1753 supportedTypes,
1754 batchToSpaceNdQueueDescriptorStr);
1755
1756 ValidateTensorDataTypesMatch(input, output, batchToSpaceNdQueueDescriptorStr, "input", "output");
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +00001757}
1758
Conor Kennedy430b5d82018-11-14 15:28:28 +00001759void StridedSliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1760{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001761 ValidateNumInputs(workloadInfo, "StridedSliceQueueDescriptor", 1);
1762 ValidateNumOutputs(workloadInfo, "StridedSliceQueueDescriptor", 1);
Conor Kennedy430b5d82018-11-14 15:28:28 +00001763
1764 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
Matteo Martincighe851b3d2019-05-28 14:31:20 +01001765 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1766
1767 std::vector<DataType> supportedTypes =
1768 {
1769 DataType::Float16,
1770 DataType::Float32,
Matteo Martincigh42666a12019-05-29 08:53:41 +01001771 DataType::QuantisedAsymm8,
1772 DataType::QuantisedSymm16
Matteo Martincighe851b3d2019-05-28 14:31:20 +01001773 };
1774
1775 ValidateDataTypes(input, supportedTypes, "StridedSliceQueueDescriptor");
1776 ValidateDataTypes(output, supportedTypes, "StridedSliceQueueDescriptor");
1777
1778 ValidateDataTypes(output, { input.GetDataType() }, "StridedSliceQueueDescriptor");
1779
1780 ValidateTensorQuantizationSpace(input, output, "StridedSliceQueueDescriptor", "input", "output");
1781
Conor Kennedy430b5d82018-11-14 15:28:28 +00001782 const uint32_t rank = input.GetNumDimensions();
1783
Nattapat Chaimanowonga0d28442018-11-21 16:48:17 +00001784 if (rank > 4)
1785 {
1786 throw InvalidArgumentException(
1787 "StridedSliceLayer: Input tensors with rank greater than 4 are not supported");
1788 }
1789
Conor Kennedy430b5d82018-11-14 15:28:28 +00001790 // Begin, End & Stride length must be of rank(input0)
1791 if (m_Parameters.m_Begin.size() != rank)
1792 {
1793 throw InvalidArgumentException("StridedSliceLayer: Begin length must be of rank input0("
1794 + to_string(rank) + ")");
1795 }
1796
1797 if (m_Parameters.m_End.size() != rank)
1798 {
1799 throw InvalidArgumentException("StridedSliceLayer: End length must be of rank input0("
1800 + to_string(rank) + ")");
1801 }
1802
1803 if (m_Parameters.m_Stride.size() != rank)
1804 {
1805 throw InvalidArgumentException("StridedSliceLayer: Stride length must be of rank input0("
1806 + to_string(rank) + ")");
1807 }
1808
1809 // Stride entries must be non-zero
1810 for (auto& stride : m_Parameters.m_Stride)
1811 {
1812 if (stride == 0)
1813 {
1814 throw InvalidArgumentException("StridedSliceLayer: Stride entries must be non-zero");
1815 }
1816 }
1817}
1818
kevmay0190539692018-11-29 08:40:19 +00001819void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1820{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001821 ValidateNumInputs(workloadInfo, "MinimumQueueDescriptor", 2);
1822 ValidateNumOutputs(workloadInfo, "MinimumQueueDescriptor", 1);
kevmay0190539692018-11-29 08:40:19 +00001823
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001824 std::vector<DataType> supportedTypes = {
1825 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001826 DataType::QuantisedAsymm8,
1827 DataType::QuantisedSymm16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001828 };
1829
1830 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1831 supportedTypes,
1832 "MinimumQueueDescriptor");
1833
1834 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1835 supportedTypes,
1836 "MinimumQueueDescriptor");
1837
1838 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1839 supportedTypes,
1840 "MinimumQueueDescriptor");
1841
kevmay0190539692018-11-29 08:40:19 +00001842 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1843 workloadInfo.m_InputTensorInfos[1],
1844 workloadInfo.m_OutputTensorInfos[0],
1845 "MinimumQueueDescriptor",
1846 "first input",
1847 "second input");
1848}
1849
Nattapat Chaimanowonga9a1cf12018-12-03 16:06:49 +00001850void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1851{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001852 ValidateNumInputs(workloadInfo, "DebugQueueDescriptor", 1);
1853 ValidateNumOutputs(workloadInfo, "DebugQueueDescriptor", 1);
Nattapat Chaimanowonga9a1cf12018-12-03 16:06:49 +00001854}
1855
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001856void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1857{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001858 ValidateNumInputs(workloadInfo, "EqualQueueDescriptor", 2);
1859 ValidateNumOutputs(workloadInfo, "EqualQueueDescriptor", 1);
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001860
1861 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1862 workloadInfo.m_InputTensorInfos[1],
1863 workloadInfo.m_OutputTensorInfos[0],
1864 "EqualQueueDescriptor",
1865 "first input",
1866 "second input");
kevmay012b4d88e2019-01-24 14:05:09 +00001867
1868 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
1869 {
1870 throw InvalidArgumentException("EqualQueueDescriptor: Output tensor type must be Boolean.");
1871 }
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001872}
1873
FrancisMurtagh878f0232018-12-19 10:56:15 +00001874void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1875{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001876 ValidateNumInputs(workloadInfo, "GreaterQueueDescriptor", 2);
1877 ValidateNumOutputs(workloadInfo, "GreaterQueueDescriptor", 1);
FrancisMurtagh878f0232018-12-19 10:56:15 +00001878
1879 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1880 workloadInfo.m_InputTensorInfos[1],
1881 workloadInfo.m_OutputTensorInfos[0],
1882 "GreaterQueueDescriptor",
1883 "first input",
1884 "second input");
kevmay012b4d88e2019-01-24 14:05:09 +00001885
1886 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
1887 {
1888 throw InvalidArgumentException("GreaterQueueDescriptor: Output tensor type must be Boolean.");
1889 }
FrancisMurtagh878f0232018-12-19 10:56:15 +00001890}
1891
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001892void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1893{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001894 ValidateNumInputs(workloadInfo, "RsqrtQueueDescriptor", 1);
1895 ValidateNumOutputs(workloadInfo, "RsqrtQueueDescriptor", 1);
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001896 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1897 workloadInfo.m_OutputTensorInfos[0],
1898 "RsqrtQueueDescriptor",
1899 "input",
1900 "output");
nikraj010421e7f2019-06-14 09:40:34 +01001901
1902 std::vector<DataType> supportedTypes =
1903 {
1904 DataType::Float16,
1905 DataType::Float32,
nikraj0124d73212019-06-14 14:20:40 +01001906 DataType::QuantisedAsymm8,
1907 DataType::QuantisedSymm16
nikraj010421e7f2019-06-14 09:40:34 +01001908 };
1909
1910 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1911 supportedTypes,
1912 "RsqrtQueueDescriptor");
1913
1914 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1915 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
1916 "RsqrtQueueDescriptor");
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001917}
1918
narpra01b89b05f2019-01-16 09:53:09 +00001919void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1920{
Ellen Norris-Thompsone0dbedf2019-06-24 09:23:38 +01001921 const std::string GatherQueueDescriptorStr = "GatherQueueDescriptor";
1922
1923 ValidateNumInputs(workloadInfo, GatherQueueDescriptorStr, 2);
1924 ValidateNumOutputs(workloadInfo, GatherQueueDescriptorStr, 1);
narpra014951d842019-01-18 16:53:53 +00001925
1926 const TensorInfo& indices = workloadInfo.m_InputTensorInfos[1];
1927
1928 if (indices.GetDataType() != DataType::Signed32)
1929 {
Ellen Norris-Thompsone0dbedf2019-06-24 09:23:38 +01001930 throw InvalidArgumentException(GatherQueueDescriptorStr + ": Indices tensor type must be int32.");
narpra014951d842019-01-18 16:53:53 +00001931 }
1932
Ellen Norris-Thompsone0dbedf2019-06-24 09:23:38 +01001933 std::vector<DataType> supportedTypes =
1934 {
1935 DataType::Float16,
1936 DataType::Float32,
1937 DataType::QuantisedAsymm8,
1938 DataType::QuantisedSymm16
1939 };
1940
1941 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1942 supportedTypes,
1943 GatherQueueDescriptorStr);
1944
1945 ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1946 workloadInfo.m_OutputTensorInfos[0],
1947 GatherQueueDescriptorStr, "Input", "Output");
1948
narpra014951d842019-01-18 16:53:53 +00001949 const TensorInfo& params = workloadInfo.m_InputTensorInfos[0];
1950 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1951 unsigned int paramsDim = params.GetNumDimensions();
1952 unsigned int indicesDim = indices.GetNumDimensions();
1953 unsigned int outputDim = paramsDim - 1 + indicesDim;
1954
Ellen Norris-Thompsone0dbedf2019-06-24 09:23:38 +01001955 ValidateTensorNumDimensions(output, GatherQueueDescriptorStr, outputDim, "output");
narpra01b89b05f2019-01-16 09:53:09 +00001956}
1957
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001958void DetectionPostProcessQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1959{
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001960 const std::string& descriptorName = " DetectionPostProcessQueueDescriptor";
1961 ValidateNumInputs(workloadInfo, descriptorName, 2);
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001962
1963 if (workloadInfo.m_OutputTensorInfos.size() != 4)
1964 {
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001965 throw InvalidArgumentException(descriptorName + ": Requires exactly four outputs. " +
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001966 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
1967 }
1968
1969 if (m_Anchors == nullptr)
1970 {
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001971 throw InvalidArgumentException(descriptorName + ": Anchors tensor descriptor is missing.");
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001972 }
1973
1974 const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001975 const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
1976 const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
1977
1978 const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
Narumol Prangnawarat6d302bf2019-02-04 11:46:26 +00001979 const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001980 const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
1981 const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001982
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001983 ValidateTensorNumDimensions(boxEncodingsInfo, descriptorName, 3, "box encodings");
1984 ValidateTensorNumDimensions(scoresInfo, descriptorName, 3, "scores");
1985 ValidateTensorNumDimensions(anchorsInfo, descriptorName, 2, "anchors");
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001986
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001987 const std::vector<DataType> supportedInputTypes =
1988 {
1989 DataType::Float32,
1990 DataType::QuantisedAsymm8,
1991 DataType::QuantisedSymm16
1992 };
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001993
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01001994 ValidateDataTypes(boxEncodingsInfo, supportedInputTypes, descriptorName);
1995 ValidateDataTypes(scoresInfo, supportedInputTypes, descriptorName);
1996 ValidateDataTypes(anchorsInfo, supportedInputTypes, descriptorName);
1997
1998 ValidateTensorNumDimensions(detectionBoxesInfo, descriptorName, 3, "detection boxes");
1999 ValidateTensorNumDimensions(detectionScoresInfo, descriptorName, 2, "detection scores");
2000 ValidateTensorNumDimensions(detectionClassesInfo, descriptorName, 2, "detection classes");
2001 ValidateTensorNumDimensions(numDetectionsInfo, descriptorName, 1, "num detections");
2002
2003 // NOTE: Output is always Float32 regardless of input type
2004 ValidateTensorDataType(detectionBoxesInfo, DataType::Float32, descriptorName, "detection boxes");
2005 ValidateTensorDataType(detectionScoresInfo, DataType::Float32, descriptorName, "detection scores");
2006 ValidateTensorDataType(detectionClassesInfo, DataType::Float32, descriptorName, "detection classes");
2007 ValidateTensorDataType(numDetectionsInfo, DataType::Float32, descriptorName, "num detections");
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00002008
2009 if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f)
2010 {
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01002011 throw InvalidArgumentException(descriptorName + ": Intersection over union threshold "
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00002012 "must be positive and less than or equal to 1.");
2013 }
2014 if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
2015 {
Aron Virginas-Tar6331f912019-06-03 17:10:02 +01002016 throw InvalidArgumentException(descriptorName + ": Number of classes with background "
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00002017 "should be equal to number of classes + 1.");
2018 }
2019}
2020
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00002021void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2022{
Sadik Armaganeff363d2019-04-05 15:25:46 +01002023 ValidateNumInputs(workloadInfo, "DequantizeQueueDescriptor", 1);
2024 ValidateNumOutputs(workloadInfo, "DequantizeQueueDescriptor", 1);
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00002025
2026 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::QuantisedAsymm8 &&
2027 workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::QuantisedSymm16)
2028 {
2029 throw InvalidArgumentException("Input to dequantize layer must be quantized type.");
2030 }
2031
2032 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float32)
2033 {
2034 throw InvalidArgumentException("Output of dequantize layer must be Float32 type.");
2035 }
2036}
2037
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01002038void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2039{
Sadik Armaganeff363d2019-04-05 15:25:46 +01002040 ValidateNumInputs(workloadInfo, "MergeQueueDescriptor", 2);
2041 ValidateNumOutputs(workloadInfo, "MergeQueueDescriptor", 1);
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01002042
2043 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
2044 workloadInfo.m_InputTensorInfos[1],
2045 "MergeQueueDescriptor",
2046 "input0",
2047 "input1");
2048
2049 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
2050 workloadInfo.m_OutputTensorInfos[0],
2051 "MergeQueueDescriptor",
2052 "input0",
2053 "output");
2054
2055 const DataType dataType = workloadInfo.m_InputTensorInfos[0].GetDataType();
2056 ValidateTensorDataType(workloadInfo.m_InputTensorInfos[1], dataType, "MergeQueueDescriptor", "input1");
2057 ValidateTensorDataType(workloadInfo.m_OutputTensorInfos[0], dataType, "MergeQueueDescriptor", "output");
2058}
2059
Sadik Armaganeff363d2019-04-05 15:25:46 +01002060void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2061{
2062 ValidateNumInputs(workloadInfo, "SwitchQueueDescriptor", 2);
2063 ValidateNumOutputs(workloadInfo, "SwitchQueueDescriptor", 2);
2064
2065 std::vector<DataType> supportedTypes = {
2066 DataType::Float32,
2067 DataType::QuantisedAsymm8,
2068 DataType::QuantisedSymm16
2069 };
2070
2071 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
2072 supportedTypes,
2073 "SwitchQueueDescriptor");
2074
2075 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
2076 supportedTypes,
2077 "SwitchQueueDescriptor");
2078
2079 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
2080 supportedTypes,
2081 "SwitchQueueDescriptor");
2082
2083 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
2084 workloadInfo.m_OutputTensorInfos[0],
2085 "SwitchQueueDescriptor",
2086 "input0",
2087 "output0");
2088
2089 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
2090 workloadInfo.m_OutputTensorInfos[1],
2091 "SwitchQueueDescriptor",
2092 "input0",
2093 "output1");
2094}
2095
Matteo Martincigh49124022019-01-11 13:25:59 +00002096void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2097{
2098 // This is internally generated so it should not need validation.
2099}
2100
Matteo Martincigh0e406ee2019-06-12 15:42:18 +01002101void PreluQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2102{
2103 ValidateNumInputs(workloadInfo, "PreluQueueDescriptor", 2);
2104 ValidateNumOutputs(workloadInfo, "PreluQueueDescriptor", 1);
2105
2106 std::vector<DataType> supportedTypes
2107 {
2108 DataType::Float16,
2109 DataType::Float32,
Matteo Martincighab9e5252019-06-13 17:27:46 +01002110 DataType::QuantisedAsymm8,
2111 DataType::QuantisedSymm16
Matteo Martincigh0e406ee2019-06-12 15:42:18 +01002112 };
2113
2114 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
2115 supportedTypes,
2116 "PreluQueueDescriptor");
2117
2118 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
2119 supportedTypes,
2120 "PreluQueueDescriptor");
2121
2122 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
2123 supportedTypes,
2124 "PreluQueueDescriptor");
2125
2126 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
2127 { workloadInfo.m_InputTensorInfos[1].GetDataType() },
2128 "PreluQueueDescriptor");
2129
2130 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
2131 { workloadInfo.m_OutputTensorInfos[0].GetDataType() },
2132 "PreluQueueDescriptor");
2133
2134 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
2135 workloadInfo.m_InputTensorInfos[1],
2136 workloadInfo.m_OutputTensorInfos[0],
2137 "PreluQueueDescriptor",
2138 "input",
2139 "alpha");
2140}
2141
Aron Virginas-Tar639fb042019-06-20 14:28:19 +01002142void TransposeConvolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2143{
2144 const std::string descriptorName{"TransposeConvolution2dQueueDescriptor"};
2145
2146 ValidateNumInputs(workloadInfo, descriptorName, 1);
2147 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2148
2149 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], descriptorName, 4, "input");
2150 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], descriptorName, 4, "output");
2151
2152 ValidatePointer(m_Weight, descriptorName, "weight");
2153 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), descriptorName, 4, "weight");
2154
2155 ValidateTensorDataType(m_Weight->GetTensorInfo(),
2156 workloadInfo.m_InputTensorInfos[0].GetDataType(),
2157 descriptorName,
2158 "weight");
2159
2160 if (m_Parameters.m_BiasEnabled)
2161 {
2162 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), descriptorName, 1, "bias");
2163
2164 ValidateTensorDataType(m_Bias->GetTensorInfo(),
2165 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
2166 descriptorName, "bias");
2167
2168 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
2169 workloadInfo.m_InputTensorInfos[0],
2170 m_Weight->GetTensorInfo(),
2171 descriptorName);
2172 }
2173
2174 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0],
2175 m_Weight->GetTensorInfo(),
2176 workloadInfo.m_OutputTensorInfos[0],
2177 descriptorName,
2178 "input",
2179 "weights",
2180 "output");
2181}
2182
Nattapat Chaimanowonga0d28442018-11-21 16:48:17 +00002183} //namespace armnn