ArmNN
 25.02
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
WorkloadData.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017-2024 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
11 #include <armnnUtils/Permute.hpp>
13 #include <armnn/Logging.hpp>
14 
15 #include <algorithm>
16 #include <iomanip>
17 #include <string>
18 #include <sstream>
19 
20 #include <fmt/format.h>
21 
22 using namespace armnnUtils;
23 
24 namespace armnn
25 {
26 
27 //---------------------------------------------------------------
29 {
30  switch (inputDataType)
31  {
32  case DataType::Float16:
33  return DataType::Float16;
34  case DataType::BFloat16:
35  case DataType::Float32:
36  return DataType::Float32;
37  case DataType::QAsymmS8:
38  case DataType::QAsymmU8:
39  case DataType::QSymmS8:
40  case DataType::QSymmS16:
41  return DataType::Signed32;
42  default:
43  throw InvalidArgumentException("GetBiasDataType(): Unsupported data type.");
44  }
45 }
46 
47 namespace
48 {
49 
50 //---------------------------------------------------------------
51 //android ndk does not support std::to_string function.
52 template <typename T>
53 std::string to_string(T value)
54 {
55  std::ostringstream os;
56  os << value;
57  return os.str();
58 }
59 
60 //---------------------------------------------------------------
61 void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName)
62 {
63  if (!ptr)
64  {
65  throw InvalidArgumentException(descName + ": Invalid null pointer. The " +
66  paramName + " parameter must be set.");
67  }
68 }
69 
70 //---------------------------------------------------------------
71 void ValidateTensorShapesMatch(const TensorInfo& first,
72  const TensorInfo& second,
73  std::string const& descName,
74  std::string const& firstName,
75  std::string const& secondName)
76 {
77  if (first.GetShape() != second.GetShape())
78  {
79  throw InvalidArgumentException(descName + ": "
80  + firstName + " & " + secondName + " must have identical shapes");
81  }
82 }
83 
84 //---------------------------------------------------------------
85 void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
86 {
87  if (workloadInfo.m_InputTensorInfos.size() != expectedSize)
88  {
89  throw InvalidArgumentException(descName +
90  ": Requires exactly " + to_string(expectedSize) + "input(s). " +
91  to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided.");
92  }
93 }
94 
95 //---------------------------------------------------------------
96 void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
97 {
98  if (workloadInfo.m_OutputTensorInfos.size() != expectedSize)
99  {
100  throw InvalidArgumentException(descName +
101  ": Requires exactly " + to_string(expectedSize) + " output(s). " +
102  to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
103  }
104 }
105 
106 //---------------------------------------------------------------
107 
108 //---------------------------------------------------------------
109 void ValidateTensorNumElements(const TensorInfo& tensor,
110  std::string const& descName,
111  unsigned int numElements,
112  std::string const& tensorName)
113 {
114  if (tensor.GetNumElements() != numElements)
115  {
116  throw InvalidArgumentException(descName + ": Expected " + to_string(numElements) + " but got " +
117  to_string(tensor.GetNumElements()) + " elements for " +
118  tensorName + " tensor.");
119  }
120 }
121 
122 //---------------------------------------------------------------
123 void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
124  const std::string& descName, std::string const& tensorName)
125 {
126  if (tensor.GetDataType() != dataType)
127  {
128  throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
129  GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
130  }
131 }
132 
133 void ValidPerAxisQuantizedDataType(const TensorInfo& tensor, const std::string& descName, const std::string& tensorName)
134 {
135  if (tensor.GetDataType() != DataType::QSymmS8)
136  {
137  throw InvalidArgumentException(descName +
138  ": Expected data type which supports per-axis quantization scheme but got " +
139  GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
140  }
141 }
142 
143 //---------------------------------------------------------------
144 void ValidateTensorQuantizationSpace(const TensorInfo& first,
145  const TensorInfo& second,
146  const std::string& descName,
147  std::string const& firstName,
148  std::string const& secondName)
149 {
150  if (!first.IsQuantized() ||
151  !second.IsQuantized())
152  {
153  // Not a quantized type, ignore the validation
154  return;
155  }
156 
157  DataType firstDataType = first.GetDataType();
158  DataType secondDataType = second.GetDataType();
159 
160  if (firstDataType != secondDataType)
161  {
162  throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
163  " must be of the same quantized type, " +
164  firstName + " is " + GetDataTypeName(firstDataType) + ", " +
165  secondName + " is " + GetDataTypeName(secondDataType));
166  }
167 
168  if (!first.IsTypeSpaceMatch(second))
169  {
170  throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
171  " must have the same quantization space, " +
172  firstName + " has offset " + to_string(first.GetQuantizationOffset()) +
173  " and scale " + to_string(first.GetQuantizationScale()) + ", " +
174  secondName + " has offset " + to_string(second.GetQuantizationOffset()) +
175  " and scale " + to_string(second.GetQuantizationScale()));
176  }
177 }
178 
179 //---------------------------------------------------------------
180 void ValidateBiasTensorQuantization(const TensorInfo& biasTensor,
181  const TensorInfo& weightsTensorInfo,
182  const std::string& descName)
183 {
184  if (biasTensor.GetQuantizationOffset() != 0)
185  {
186  throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
187  to_string(biasTensor.GetQuantizationOffset()));
188  }
189 
190  if (biasTensor.HasMultipleQuantizationScales() || weightsTensorInfo.HasMultipleQuantizationScales())
191  {
192  // Validate per-axis quantization scales
193  const std::vector<float>& weightScales = weightsTensorInfo.GetQuantizationScales();
194  const std::vector<float>& biasScales = biasTensor.GetQuantizationScales();
195 
196  if (weightScales.size() != biasScales.size())
197  {
198  std::stringstream msg;
199  msg << descName << ": Expected matching number of per-axis quantization scales for weights and bias, "
200  << "but got different values. This is currently unsupported: weights=" << weightScales.size()
201  << ", biases=" << biasScales.size();
202  throw InvalidArgumentException(msg.str(), CHECK_LOCATION());
203  }
204  }
205 }
206 
207 //---------------------------------------------------------------
208 void ValidateTensors(const std::vector<ITensorHandle*>& vec,
209  unsigned int numExpected,
210  const std::string& descName,
211  const std::string& varName)
212 {
213  if (vec.empty() && numExpected > 0)
214  {
215  throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
216  }
217 
218  for (unsigned int i = 0; i < numExpected; ++i)
219  {
220  if (!vec[i])
221  {
222  throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
223  }
224  }
225 }
226 
227 //---------------------------------------------------------------
228 void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
229  const TensorInfo& second,
230  const TensorInfo& output,
231  std::string const& descName,
232  std::string const& firstName,
233  std::string const& secondName)
234 {
235  // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
236  // broadcasted.
237  // NOTE: This check is dependent on the AddBroadcastReshapeLayerImpl optimization having been applied to the layer.
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(armnn::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 void ValidateDataTypes(const TensorInfo& info,
267  const std::vector<armnn::DataType>& supportedTypes,
268  std::string const& descName)
269 {
270  auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
271  if (iterator == supportedTypes.end())
272  {
273  throw InvalidArgumentException(descName + ": " + " Tensor type " + GetDataTypeName(info.GetDataType()) +
274  " is not supported.");
275  }
276 }
277 
278 //---------------------------------------------------------------
279 void ValidateTensorDataTypesMatch(const TensorInfo& first,
280  const TensorInfo& second,
281  std::string const& descName,
282  std::string const& firstName,
283  std::string const& secondName)
284 {
285  if (first.GetDataType() != second.GetDataType())
286  {
287  throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
288  " must have identical data types.");
289  }
290 }
291 
292 //---------------------------------------------------------------
293 void ValidateTensorNumElementsMatch(const TensorInfo& first,
294  const TensorInfo& second,
295  std::string const& descName,
296  std::string const& firstName,
297  std::string const& secondName)
298 {
299  if (first.GetNumElements() != second.GetNumElements())
300  {
301  throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
302  " must have the same number of elements.");
303  }
304 }
305 
306 void ValidateWeightDataType(const TensorInfo& inputInfo,
307  const TensorInfo& weightInfo,
308  const std::string& descName)
309 {
310  const DataType inputType = inputInfo.GetDataType();
311  if (IsQuantized8BitType(inputType))
312  {
313  const std::vector<DataType> validTypes =
314  {
315  DataType::QAsymmS8,
316  DataType::QAsymmU8,
317  DataType::QSymmS8
318  };
319 
320  ValidateDataTypes(weightInfo, validTypes, descName);
321  }
322  else
323  {
324  ValidateTensorDataTypesMatch(inputInfo, weightInfo, descName, "input", "weight");
325  }
326 }
327 
328 void ValidatePerAxisQuantizationDimension(const TensorInfo& tensorInfo,
329  const std::string& descName,
330  const std::string& tensorName)
331 {
332  const Optional<unsigned int>& quantizationDim = tensorInfo.GetQuantizationDim();
333  if (!quantizationDim.has_value())
334  {
335  throw InvalidArgumentException(fmt::format("{0}: Quantization dimension for per-axis quantization "
336  "not set on tensor {1}.", descName, tensorName));
337  }
338 }
339 
340 void ValidatePerAxisQuantizationOffset(const TensorInfo& tensorInfo,
341  const std::string& descName,
342  const std::string& tensorName)
343 {
344  int32_t quantizationOffset = tensorInfo.GetQuantizationOffset();
345  if (quantizationOffset != 0)
346  {
347  throw InvalidArgumentException(fmt::format(
348  "{0}: Quantization offset for per-axis quantization expected to be 0 on tensor {1}, but got: {2}",
349  descName, tensorName, quantizationOffset));
350  }
351 }
352 
353 void ValidatePerAxisQuantization(const TensorInfo& inputInfo,
354  const TensorInfo& outputInfo,
355  const TensorInfo& weightInfo,
356  const Optional<TensorInfo>& optionalBiasInfo,
357  const std::string& descName)
358 {
359  if (weightInfo.HasPerAxisQuantization())
360  {
361  const DataType inputDataType = inputInfo.GetDataType();
362  const DataType outputDataType = outputInfo.GetDataType();
363 
364  const bool canHavePerAxisQuantization = (IsQuantized8BitType(inputDataType)) && inputDataType == outputDataType;
365 
366  if (!canHavePerAxisQuantization)
367  {
368  throw InvalidArgumentException(fmt::format(
369  "{0}: Per-axis quantization parameters set on tensor {1}, but data type does not support "
370  "per-axis quantization.", descName, "weight"));
371  }
372 
373 
374  ValidPerAxisQuantizedDataType(weightInfo, descName, "weight");
375  ValidatePerAxisQuantizationDimension(weightInfo, descName, "weight");
376  ValidatePerAxisQuantizationOffset(weightInfo, descName, "weight");
377 
378  if (optionalBiasInfo.has_value())
379  {
380  const TensorInfo& biasInfo = optionalBiasInfo.value();
381  if (!biasInfo.HasPerAxisQuantization())
382  {
383  throw InvalidArgumentException(fmt::format(
384  "{}: Per-axis quantization parameters not set on bias tensor, "
385  "despite being set on weight tensor.", descName));
386  }
387 
388  ValidateTensorDataType(biasInfo, DataType::Signed32, descName, "bias");
389  ValidatePerAxisQuantizationDimension(biasInfo, descName, "bias");
390  ValidatePerAxisQuantizationOffset(biasInfo, descName, "bias");
391  }
392  }
393 }
394 
395 } // anonymous namespace
396 
397 //---------------------------------------------------------------
399  std::string const& descName,
400  unsigned int numDimensions,
401  std::string const& tensorName) const
402 {
403  // If we're allowing expanded dimensions then numDimensions becomes the minimum number of Dimensions we can allow.
404  // Throw an Exception if the tensors has fewer than numDimensions or if the squeezed dimensions are greater than
405  // numDimensions.
407  {
408  unsigned int squeezedDims = 0;
409 
410  for (unsigned int i = 0; i < tensor.GetNumDimensions(); ++i)
411  {
412  if (tensor.GetShape()[i] != 1)
413  {
414  ++squeezedDims;
415  }
416  }
417  if (tensor.GetNumDimensions() < numDimensions || squeezedDims > numDimensions)
418  {
419  throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " or less but got " +
420  to_string(tensor.GetNumDimensions()) + " dimensions for " +
421  tensorName + " tensor.");
422  }
423  }
424  else
425  {
426  if (tensor.GetNumDimensions() != numDimensions)
427  {
428  throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " +
429  to_string(tensor.GetNumDimensions()) + " dimensions for " +
430  tensorName + " tensor.");
431  }
432  }
433 }
434 
435 //---------------------------------------------------------------
437  unsigned int numDimension,
438  unsigned int numElements,
439  std::string const& tensorName) const
440 {
441  const std::string functionName{"ValidateTensorNumDimNumElem"};
442  ValidateTensorNumDimensions(tensorInfo, functionName, numDimension, tensorName);
443  ValidateTensorNumElements(tensorInfo, functionName, numElements, tensorName);
444 }
445 
446 //---------------------------------------------------------------
447 void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
448  unsigned int numExpectedIn, unsigned int numExpectedOut) const
449 {
450  ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
451  ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
452 }
453 
454 //---------------------------------------------------------------
455 void MapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
456 {
457  const std::string descriptorName{"MapQueueDescriptor"};
458 
459  ValidateNumInputs(workloadInfo, descriptorName, 1);
460  ValidateNumOutputs(workloadInfo, descriptorName, 0);
461 
462  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
463  {
464  if (!m_Inputs[i])
465  {
467  fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
468  }
469  }
470 }
471 
472 //---------------------------------------------------------------
473 void UnmapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
474 {
475  const std::string descriptorName{"UnmapQueueDescriptor"};
476 
477  ValidateNumInputs(workloadInfo, descriptorName, 1);
478  ValidateNumOutputs(workloadInfo, descriptorName, 0);
479 
480  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
481  {
482  if (!m_Inputs[i])
483  {
485  fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
486  }
487  }
488 }
489 
490 //---------------------------------------------------------------
491 void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
492 {
493  const std::string descriptorName{"MemCopyQueueDescriptor"};
494 
495  ValidateNumInputs(workloadInfo, descriptorName, 1);
496  ValidateNumOutputs(workloadInfo, descriptorName , 1);
497 
498  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
499  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
500 
501  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
502  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
503 
504  if (m_Inputs.size() != m_Outputs.size())
505  {
506  throw InvalidArgumentException(fmt::format(
507  "{0}: Number of inputs ({1}) does not match the number of outputs ({2}).",
508  descriptorName, m_Inputs.size(), m_Outputs.size()));
509  }
510 
511  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
512  {
513  if (!m_Inputs[i])
514  {
515  throw InvalidArgumentException(fmt::format(
516  "{0}: Invalid NULL input {1}.", descriptorName, i));
517  }
518 
519  if (!m_Outputs[i])
520  {
521  throw InvalidArgumentException(fmt::format("{0}: Invalid NULL output {1}", descriptorName, i));
522  }
523  }
524 }
525 
526 //---------------------------------------------------------------
527 void MemImportQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
528 {
529  ValidateNumInputs(workloadInfo, "MemImportQueueDescriptor", 1);
530  ValidateNumOutputs(workloadInfo, "MemImportQueueDescriptor" , 1);
531 
532  if (workloadInfo.m_InputTensorInfos.size() != 1)
533  {
534  throw InvalidArgumentException(fmt::format("Number of input infos ({}) is not 1.",
535  workloadInfo.m_InputTensorInfos.size()));
536 
537  }
538 
539  if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
540  {
541  throw InvalidArgumentException(fmt::format(
542  "Number of input infos ({0}) does not match the number of output infos ({1})",
543  workloadInfo.m_InputTensorInfos.size(), workloadInfo.m_OutputTensorInfos.size()));
544  }
545 
546  for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
547  {
548  if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
549  workloadInfo.m_OutputTensorInfos[i].GetNumElements())
550  {
551  throw InvalidArgumentException(fmt::format(
552  "Number of elements for tensor input and output {} does not match", i ));
553  }
554  }
555 
556  if (m_Inputs.size() != 1)
557  {
558  throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
559  }
560 
561  if (m_Inputs.size() != m_Outputs.size())
562  {
563  throw InvalidArgumentException(fmt::format(
564  "Number of inputs ({0}) does not match the number of outputs ({1})",
565  m_Inputs.size(), m_Outputs.size()));
566  }
567 
568  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
569  {
570  if (!m_Inputs[i])
571  {
572  throw InvalidArgumentException(fmt::format("Invalid null input {}", i));
573  }
574 
575  if (!m_Outputs[i])
576  {
577  throw InvalidArgumentException(fmt::format("Invalid null output {}", i));
578  }
579  }
580 }
581 
582 //---------------------------------------------------------------
583 void MemSyncQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
584 {
585  ValidateNumInputs(workloadInfo, "MemSyncQueueDescriptor", 1);
586 
587  if (m_Inputs.size() != 1)
588  {
589  throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
590  }
591 
592  if (m_Outputs.size() != 0)
593  {
594  throw InvalidArgumentException(fmt::format("Number of outputs ({}) is not 0.", m_Outputs.size()));
595  }
596 
597  if (!m_Inputs[0])
598  {
599  throw InvalidArgumentException(fmt::format("Invalid null input 0"));
600  }
601 }
602 
603 //---------------------------------------------------------------
604 void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
605 {
606  const std::string descriptorName{"ActivationQueueDescriptor"};
607 
608  ValidateNumInputs(workloadInfo, descriptorName, 1);
609  ValidateNumOutputs(workloadInfo, descriptorName, 1);
610 
611  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
612  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
613 
614  std::vector<DataType> supportedTypes =
615  {
622  };
623 
624  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
625  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
626  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
627 }
628 
629 void ArgMinMaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
630 {
631  const std::string descriptorName{"ArgMinMaxQueueDescriptor"};
632 
633  ValidateNumInputs(workloadInfo, descriptorName, 1);
634  ValidateNumOutputs(workloadInfo, descriptorName, 1);
635 
636  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
637  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
638 
639  if (outputTensorInfo.GetDataType() != DataType::Signed32 &&
640  outputTensorInfo.GetDataType() != DataType::Signed64)
641  {
642  throw InvalidArgumentException(descriptorName + ": Output of ArgMinMax layer must be Int32 or Int64.");
643  }
644 
645  std::vector<DataType> supportedInputTypes =
646  {
655  };
656 
657  ValidateDataTypes(inputTensorInfo, supportedInputTypes, descriptorName);
658 
659  auto inputShape = inputTensorInfo.GetShape();
660  auto outputShape = outputTensorInfo.GetShape();
661 
662  auto inputNumDimensions = inputShape.GetNumDimensions();
663  auto unsignedAxis = armnnUtils::GetUnsignedAxis(inputNumDimensions, m_Parameters.m_Axis);
664 
665  const std::string outputShapeError{": Output tensor shape does not match shape inferred from input tensor."};
666 
667  // 1D input shape results in scalar output shape
668  if (inputShape.GetNumDimensions() == 1)
669  {
670  if (outputShape.GetNumDimensions() != 1 && outputShape[0] != 1)
671  {
672  throw InvalidArgumentException(descriptorName + outputShapeError);
673  }
674  }
675  else
676  {
677  for (unsigned int i = 0; i < unsignedAxis; ++i)
678  {
679  if (outputShape[i] != inputShape[i])
680  {
681  throw InvalidArgumentException(descriptorName + outputShapeError);
682  }
683  }
684 
685  for (auto i = unsignedAxis + 1; i < inputNumDimensions; ++i)
686  {
687  if (outputShape[i - 1] != inputShape[i])
688  {
689  throw InvalidArgumentException(descriptorName + outputShapeError);
690  }
691  }
692  }
693 }
694 
695 void CastQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
696 {
697  const std::string descriptorName{"CastQueueDescriptor"};
698 
699  ValidateNumInputs(workloadInfo, descriptorName, 1);
700  ValidateNumOutputs(workloadInfo, descriptorName, 1);
701 
702  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
703  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
704 
705  std::vector<DataType> supportedTypes =
706  {
717  };
718 
719  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
720  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
721 }
722 
723 void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
724 {
725  const std::string descriptorName{"SoftmaxQueueDescriptor"};
726 
727  ValidateNumInputs(workloadInfo, descriptorName, 1);
728  ValidateNumOutputs(workloadInfo, descriptorName, 1);
729 
730  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
731  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
732 
733  std::vector<DataType> supportedTypes =
734  {
741  };
742 
743  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
744  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
745  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
746 }
747 
748 void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
749 {
750  const std::string descriptorName{"SplitterQueueDescriptor"};
751 
752  ValidateNumInputs(workloadInfo, descriptorName, 1);
753 
754  // Check the supported data types
755  std::vector<DataType> supportedTypes =
756  {
765  };
766 
767  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
768  for (unsigned long i = 0ul; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
769  {
770  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[i];
771  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
772 
773  const std::string outputName = "output_" + std::to_string(i);
774  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", outputName);
775  }
776 
777  if (workloadInfo.m_OutputTensorInfos.size() <= 0)
778  {
779  throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
780  }
781 
782  if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
783  {
785  descriptorName + ": Number of split windows "
786  "has to match number of workloadInfo.m_OutputTensorInfos. "
787  "Number of windows: " +
788  to_string(m_ViewOrigins.size()) +
789  ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
790  }
791 
792  //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
793  std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
794  for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
795  {
796  //Checks that the dimensionality of input is same as the split windows.
797  ViewOrigin const& e = m_ViewOrigins[w];
798  if (e.m_Origin.size() != inputDims)
799  {
800  throw InvalidArgumentException(descriptorName + ": Window origin have to "
801  "have the same dimensionality as the input tensor. "
802  "Window origin (index: " +
803  to_string(w) + ") has " + to_string(e.m_Origin.size()) +
804  " dimensions, the input "
805  "tensor has " +
806  to_string(inputDims) + " dimensions.");
807  }
808  for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
809  {
810  if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
811  workloadInfo.m_InputTensorInfos[0].GetShape()[i])
812  {
813  throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
814  "be smaller or equal than the size of the input in that coord.");
815  }
816  }
817  }
818 }
819 
820 void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
821 {
822  const std::string descriptorName{"ConcatQueueDescriptor"};
823 
824  ValidateNumOutputs(workloadInfo, descriptorName, 1);
825 
826  if (m_Inputs.size() <= 0)
827  {
828  throw InvalidArgumentException(descriptorName + ": At least one input needs to be provided.");
829  }
830  if (m_Outputs.size() <= 0)
831  {
832  throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
833  }
834 
835  if (workloadInfo.m_InputTensorInfos.size() <= 0)
836  {
837  throw InvalidArgumentException(descriptorName + ": At least one TensorInfo input needs to be provided.");
838  }
839  if (workloadInfo.m_OutputTensorInfos.size() <= 0)
840  {
841  throw InvalidArgumentException(descriptorName + ": At least one TensorInfo output needs to be provided.");
842  }
843 
844  if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
845  {
846  throw InvalidArgumentException(descriptorName + ": Invalid concatenation axis provided.");
847  }
848 
849  if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
850  {
851  return;
852  }
853 
854  if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
855  {
857  descriptorName + ": Number of split windows "
858  "has to match number of workloadInfo.m_InputTensorInfos. "
859  "Number of windows: " +
860  to_string(m_ViewOrigins.size()) +
861  ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
862  }
863 
864  //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
865  std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
866  for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
867  {
868  //Checks that the dimensionality of output is same as the split windows.
869  ViewOrigin const& e = m_ViewOrigins[w];
870  if (e.m_Origin.size() != outputDims)
871  {
872  throw InvalidArgumentException(descriptorName + ": Window origin have to "
873  "have the same dimensionality as the output tensor. "
874  "Window origin (index: " +
875  to_string(w) + ") has " + to_string(e.m_Origin.size()) +
876  " dimensions, the output "
877  "tensor has " +
878  to_string(outputDims) + " dimensions.");
879  }
880  //Checks that the merge windows are within the output tensor.
881  for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
882  {
883  if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
884  > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
885  {
886  throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
887  "be smaller or equal than the size of the output in that coord.");
888  }
889  }
890  }
891 
892  // Check the supported data types
893  std::vector<DataType> supportedTypes =
894  {
903  };
904 
905  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
906  for (unsigned long i = 0ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
907  {
908  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[i];
909  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
910 
911  const std::string inputName = "input_" + std::to_string(i);
912  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, inputName, "output");
913  }
914 }
915 
916 void StackQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
917 {
918  const std::string descriptorName{"StackQueueDescriptor"};
919 
920  ValidateNumOutputs(workloadInfo, descriptorName, 1);
921 
922  if (m_Parameters.m_NumInputs != workloadInfo.m_InputTensorInfos.size())
923  {
924  throw InvalidArgumentException(descriptorName + ": Must have the defined number of input tensors.");
925  }
926 
927  // All inputs must have the same shape, which is defined in parameters
928  const TensorShape& inputShape = m_Parameters.m_InputShape;
929  for (unsigned int i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
930  {
931  if (workloadInfo.m_InputTensorInfos[i].GetShape() != inputShape)
932  {
933  throw InvalidArgumentException(descriptorName + ": All input tensor shapes must match the defined shape.");
934  }
935  }
936 
937  if (inputShape.GetNumDimensions() > 4)
938  {
939  throw InvalidArgumentException(descriptorName + ": Input tensor may have up to 4 dimensions.");
940  }
941 
942  // m_Axis is 0-based and may take values from 0 to the number of input dimensions (inclusive),
943  // since the output tensor has an additional dimension.
944  if (m_Parameters.m_Axis > inputShape.GetNumDimensions())
945  {
946  throw InvalidArgumentException(descriptorName + ": Axis may not be greater "
947  "than the number of input dimensions.");
948  }
949 
950  // Output shape must be as inferred from the input shape
951  const TensorShape& outputShape = workloadInfo.m_OutputTensorInfos[0].GetShape();
952  for (unsigned int i = 0; i < m_Parameters.m_Axis; ++i)
953  {
954  if (outputShape[i] != inputShape[i])
955  {
956  throw InvalidArgumentException(descriptorName + ": Output tensor must "
957  "match shape inferred from input tensor.");
958  }
959  }
960 
961  if (outputShape[m_Parameters.m_Axis] != m_Parameters.m_NumInputs)
962  {
963  throw InvalidArgumentException(descriptorName + ": Output tensor must "
964  "match shape inferred from input tensor.");
965  }
966 
967  for (unsigned int i = m_Parameters.m_Axis + 1; i < inputShape.GetNumDimensions() + 1; ++i)
968  {
969  if (outputShape[i] != inputShape[i-1])
970  {
971  throw InvalidArgumentException(descriptorName + ": Output tensor must "
972  "match shape inferred from input tensor.");
973  }
974  }
975 
976  if (outputShape.GetNumDimensions() > 5)
977  {
978  throw InvalidArgumentException(descriptorName + ": Output tensor may have up to 5 dimensions.");
979  }
980 
981  // Check the supported data types
982  std::vector<DataType> supportedTypes =
983  {
993  };
994 
995  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
996 
997  for (unsigned int i = 1ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
998  {
999  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1000  workloadInfo.m_InputTensorInfos[i],
1001  descriptorName,
1002  "input_0",
1003  "input_" + std::to_string(i));
1004  }
1005 
1006  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1007  workloadInfo.m_OutputTensorInfos[0],
1008  descriptorName,
1009  "input_0",
1010  "output");
1011 }
1012 
1013 void FillQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1014 {
1015  const std::string descriptorName{"FillQueueDescriptor"};
1016 
1017  ValidateNumInputs(workloadInfo, descriptorName, 1);
1018  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1019 
1020  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1021  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1022 
1023  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 1, "input");
1024 
1025  std::vector<DataType> supportedTypes =
1026  {
1031  };
1032 
1033  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1034 }
1035 
1037 {
1038  const std::string descriptorName{"FullyConnectedQueueDescriptor"};
1039 
1040  uint32_t numInputs = 2;
1042  {
1043  numInputs = 3;
1044  }
1045 
1046  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1047  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1048 
1049  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1050  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1051 
1052  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1053 
1054  if (!(inputTensorInfo.GetNumDimensions() == 2 || inputTensorInfo.GetNumDimensions() == 4))
1055  {
1056  throw InvalidArgumentException(descriptorName + ": Input tensor must have 2 or 4 dimensions.");
1057  }
1058 
1059  TensorInfo weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1060  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 2, "weight");
1061 
1063  {
1064  TensorInfo biasTensorInfo = workloadInfo.m_InputTensorInfos[2];
1065  // Validates type and quantization values.
1066  ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
1067  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1068  ValidateTensorNumDimensions(biasTensorInfo, descriptorName, 1, "bias");
1069  }
1070 
1071  // Check the supported data types
1072  std::vector<DataType> supportedTypes =
1073  {
1081  };
1082 
1083  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1084 
1085  // For FullyConnected, we allow to have BFloat16 input with Float32 output for optimization.
1086  if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1087  {
1088  if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1089  {
1090  throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1091  "for BFloat16 input.");
1092  }
1093  }
1094  else
1095  {
1096  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1097  }
1098 }
1099 
1100 void FusedQueueDescriptor::Validate(const WorkloadInfo& /*workloadInfo*/) const
1101 {
1102  // This is internally generated, so it should not need validation.
1103 }
1104 
1106 {
1107  const std::string descriptorName{"NormalizationQueueDescriptor"};
1108 
1109  ValidateNumInputs(workloadInfo, descriptorName, 1);
1110  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1111 
1112  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1113  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1114 
1115  // Check the supported data types
1116  std::vector<DataType> supportedTypes =
1117  {
1124  };
1125 
1126  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1127 
1128  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1129 
1130  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1131 }
1132 
1133 void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1134 {
1135  const std::string descriptorName{"AdditionQueueDescriptor"};
1136 
1137  ValidateNumInputs(workloadInfo, descriptorName, 2);
1138  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1139 
1140  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1141  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1142  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1143 
1144  std::vector<DataType> supportedTypes =
1145  {
1153  };
1154 
1155  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1156  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1157  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1158 
1159  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1160  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1161 
1162  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1163  inputTensorInfo1,
1164  outputTensorInfo,
1165  descriptorName,
1166  "input_0",
1167  "input_1");
1168 }
1169 
1171 {
1172  const std::string descriptorName{"MultiplicationQueueDescriptor"};
1173 
1174  ValidateNumInputs(workloadInfo, descriptorName, 2);
1175  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1176 
1177  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1178  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1179  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1180 
1181  std::vector<DataType> supportedTypes =
1182  {
1190  };
1191 
1192  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1193  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1194  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1195 
1196  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1197  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1198 
1199  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1200  inputTensorInfo1,
1201  outputTensorInfo,
1202  descriptorName,
1203  "input_0",
1204  "input_1");
1205 }
1206 
1208 {
1209  const std::string descriptorName{"BatchNormalizationQueueDescriptor"};
1210 
1211  ValidateNumInputs(workloadInfo, descriptorName, 1);
1212  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1213 
1214  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1215  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1216 
1217  std::vector<DataType> supportedTypes =
1218  {
1225  };
1226 
1227  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1228  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1229 
1230  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1231  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1232 
1233  ValidatePointer(m_Mean, descriptorName, "mean");
1234  ValidatePointer(m_Variance, descriptorName, "variance");
1235  ValidatePointer(m_Beta, descriptorName, "beta");
1236  ValidatePointer(m_Gamma, descriptorName, "gamma");
1237 
1238  const TensorInfo& mean = m_Mean->GetTensorInfo();
1239  const TensorInfo& variance = m_Variance->GetTensorInfo();
1240  const TensorInfo& beta = m_Beta->GetTensorInfo();
1241  const TensorInfo& gamma = m_Gamma->GetTensorInfo();
1242 
1243  ValidateTensorNumDimensions(mean, descriptorName, 1, "mean");
1244  ValidateTensorNumDimensions(variance, descriptorName, 1, "variance");
1245  ValidateTensorNumDimensions(beta, descriptorName, 1, "beta");
1246  ValidateTensorNumDimensions(gamma, descriptorName, 1, "gamma");
1247 
1248  ValidateTensorShapesMatch(mean, variance, descriptorName, "mean", "variance");
1249  ValidateTensorShapesMatch(mean, beta, descriptorName, "mean", "beta");
1250  ValidateTensorShapesMatch(mean, gamma, descriptorName, "mean", "gamma");
1251 }
1252 
1254 {
1255  const std::string descriptorName{"Convolution2dQueueDescriptor"};
1256 
1257  uint32_t numInputs = 2;
1259  {
1260  numInputs = 3;
1261  }
1262 
1263  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1264  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1265 
1266  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1267  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1268 
1269  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1270  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1271 
1272  const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1273 
1274  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1275 
1276  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1277 
1278  Optional<TensorInfo> optionalBiasTensorInfo;
1280  {
1281  optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1282  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1283 
1284  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1285  ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
1286  }
1287 
1288  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1289  {
1291  fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1292  "cannot be either negative or 0.",
1293  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1294  }
1295 
1296  ValidatePerAxisQuantization(inputTensorInfo,
1297  outputTensorInfo,
1298  weightTensorInfo,
1299  optionalBiasTensorInfo,
1300  descriptorName);
1301 
1302  std::vector<DataType> supportedTypes =
1303  {
1311  };
1312 
1313  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1314 
1315  // For Convolution2d, we allow to have BFloat16 input with Float32 output for optimization.
1316  if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1317  {
1318  if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1319  {
1320  throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1321  "for BFloat16 input.");
1322  }
1323  }
1324  else
1325  {
1326  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1327  }
1328 }
1329 
1331 {
1332  const std::string descriptorName{"Convolution3dQueueDescriptor"};
1333 
1334  uint32_t numInputs = 2;
1336  {
1337  numInputs = 3;
1338  }
1339  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1340  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1341 
1342  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1343  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1344 
1345  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 5, "input");
1346  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 5, "output");
1347 
1348  const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1349  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 5, "weight");
1350 
1351  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1352 
1353  Optional<TensorInfo> optionalBiasTensorInfo;
1355  {
1356  optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1357  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1358 
1359  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1360  ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
1361  }
1362 
1364  {
1366  fmt::format("{}: strideX (provided {}), strideY (provided {}) or strideZ (provided {})"
1367  "cannot be either negative or 0.",
1369  }
1370 
1371  ValidatePerAxisQuantization(inputTensorInfo,
1372  outputTensorInfo,
1373  weightTensorInfo,
1374  optionalBiasTensorInfo,
1375  descriptorName);
1376 
1377  std::vector<DataType> supportedTypes =
1378  {
1386  };
1387 
1388  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1389  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1390 }
1391 
1393 {
1394  const std::string descriptorName{"DepthwiseConvolution2dQueueDescriptor"};
1395 
1396  uint32_t numInputs = 2;
1398  {
1399  numInputs = 3;
1400  }
1401 
1402  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1403  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1404 
1405  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1406  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1407 
1408  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1409  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1410 
1411  const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1412  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1413 
1415  {
1417  fmt::format("{}: dilationX (provided {}) and dilationY (provided {}) "
1418  "cannot be smaller than 1.",
1419  descriptorName, m_Parameters.m_DilationX, m_Parameters.m_DilationX));
1420  }
1421 
1422  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1423  {
1425  fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1426  "cannot be either negative or 0.",
1427  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1428  }
1429 
1430  if (weightTensorInfo.GetShape()[0] != 1)
1431  {
1432  throw InvalidArgumentException(fmt::format(
1433  "{0}: The weight format in armnn is expected to be [1, H, W, Cout]."
1434  "But first dimension is not equal to 1. Provided weight shape: [{1}, {2}, {3}, {4}]",
1435  descriptorName,
1436  weightTensorInfo.GetShape()[0],
1437  weightTensorInfo.GetShape()[1],
1438  weightTensorInfo.GetShape()[2],
1439  weightTensorInfo.GetShape()[3]));
1440  }
1441 
1442  const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
1443  const unsigned int numWeightOutputChannelsRefFormat = weightTensorInfo.GetShape()[3];
1444  const unsigned int numWeightOutputChannelsAclFormat = weightTensorInfo.GetShape()[1];
1445  const unsigned int numOutputChannels = outputTensorInfo.GetShape()[channelIndex];
1446 
1447  // Weights format has two valid options: [1, H, W, Cout] (CpuRef) or [1, Cout, H, W] (CpuAcc/GpuAcc).
1448  bool validRefFormat = (numWeightOutputChannelsRefFormat == numOutputChannels);
1449  bool validAclFormat = (numWeightOutputChannelsAclFormat == numOutputChannels);
1450 
1451  if (!(validRefFormat || validAclFormat))
1452  {
1453  throw InvalidArgumentException(fmt::format(
1454  "{0}: The weight format in armnn is expected to be [1, H, W, Cout] (CpuRef) or [1, Cout, H, W] "
1455  "(CpuAcc/GpuAcc). But neither the 4th (CpuRef) or 2nd (CpuAcc/GpuAcc) dimension is equal to Cout."
1456  "Cout = {1} Provided weight shape: [{2}, {3}, {4}, {5}]",
1457  descriptorName,
1458  numOutputChannels,
1459  weightTensorInfo.GetShape()[0],
1460  weightTensorInfo.GetShape()[1],
1461  weightTensorInfo.GetShape()[2],
1462  weightTensorInfo.GetShape()[3]));
1463  }
1464 
1465  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1466 
1467  Optional<TensorInfo> optionalBiasTensorInfo;
1469  {
1470  optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1471  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1472 
1473  ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
1474  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1475  }
1476  ValidatePerAxisQuantization(inputTensorInfo,
1477  outputTensorInfo,
1478  weightTensorInfo,
1479  optionalBiasTensorInfo,
1480  descriptorName);
1481 
1482  std::vector<DataType> supportedTypes =
1483  {
1490  };
1491 
1492  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1493  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1494 }
1495 
1496 void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1497 {
1498  const std::string descriptorName{"PermuteQueueDescriptor"};
1499 
1500  ValidateNumInputs(workloadInfo, descriptorName, 1);
1501  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1502 
1503  const PermutationVector& mapping = m_Parameters.m_DimMappings;
1504 
1505  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1506  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1507 
1508  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
1509  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
1510 
1511  for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
1512  {
1513  if (inputTensorInfo.GetShape()[i] != outputTensorInfo.GetShape()[mapping[i]])
1514  {
1515  throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(i) +
1516  " (=" + to_string(inputTensorInfo.GetShape()[i]) + ") " +
1517  "must match dst dimension " + to_string(mapping[i]) +
1518  " (=" + to_string(outputTensorInfo.GetShape()[mapping[i]]) + ")");
1519  }
1520  }
1521 
1522  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1523 }
1524 
1525 void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1526 {
1527  const std::string descriptorName{"Pooling2dQueueDescriptor"};
1528 
1529  ValidateNumInputs(workloadInfo, descriptorName, 1);
1530  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1531 
1532  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1533  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1534 
1535  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1536  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1537 
1538  std::vector<DataType> supportedTypes =
1539  {
1546  };
1547 
1548  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1549  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1550 }
1551 
1552 void Pooling3dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1553 {
1554  const std::string descriptorName{"Pooling3dQueueDescriptor"};
1555 
1556  ValidateNumInputs(workloadInfo, descriptorName, 1);
1557  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1558 
1559  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1560  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1561 
1562  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 5, "input");
1563  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 5, "output");
1564 
1565  std::vector<DataType> supportedTypes =
1566  {
1573  };
1574 
1575  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1576  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1577 }
1578 
1579 void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1580 {
1581  const std::string descriptorName{"ResizeQueueDescriptor"};
1582 
1583  ValidateNumInputs(workloadInfo, descriptorName, 1);
1584  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1585 
1586  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1587  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1588 
1589  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1590  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1591 
1592  std::vector<DataType> supportedTypes =
1593  {
1601  };
1602 
1603  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1604  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1605 
1606  // Resize only changes width and height: batch and channel count must match.
1607  const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0];
1608  const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0];
1609  if (inputBatchSize != outputBatchSize)
1610  {
1612  fmt::format("{}: Input batch size ({}) does not match output batch size ({})",
1613  descriptorName, inputBatchSize, outputBatchSize));
1614  }
1615 
1616  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1617  const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1618  const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1619  if (inputChannelCount != outputChannelCount)
1620  {
1622  fmt::format("{}: Input channel count ({}) does not match output channel count ({})",
1623  descriptorName, inputChannelCount, outputChannelCount));
1624  }
1625 }
1626 
1627 void ReverseV2QueueDescriptor::Validate(const WorkloadInfo &workloadInfo) const
1628 {
1629  const std::string descriptorName{"ReverseV2QueueDescriptor"};
1630 
1631  // Backend restriction
1632  const unsigned int maxDimensions = 4;
1633 
1634  ValidateNumInputs(workloadInfo, descriptorName, 2);
1635  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1636 
1637  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1638  const TensorInfo& axisTensorInfo = workloadInfo.m_InputTensorInfos[1];
1639  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1640 
1641  const auto inputTensorNumDimensions = inputTensorInfo.GetNumDimensions();
1642  if (inputTensorNumDimensions > maxDimensions)
1643  {
1644  throw InvalidArgumentException(descriptorName +
1645  ": Input tensors with rank greater than " +
1646  std::to_string(maxDimensions) + " are not supported.");
1647  }
1648 
1649  const auto axisTensorNumDimensions = axisTensorInfo.GetNumDimensions();
1650  if (axisTensorNumDimensions > maxDimensions)
1651  {
1652  throw InvalidArgumentException(descriptorName +
1653  ": More than " + std::to_string(maxDimensions) + " axes cannot be specified.");
1654  }
1655 
1656  if (axisTensorNumDimensions > inputTensorNumDimensions)
1657  {
1658  throw InvalidArgumentException(descriptorName +
1659  ": More axes specified than the number of axes on the input tensor.");
1660  }
1661 
1662  std::vector<DataType> supportedTypes =
1663  {
1673  };
1674 
1675  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1676 
1677  std::vector<DataType> axisSupportedTypes =
1678  {
1680  };
1681 
1682  ValidateDataTypes(axisTensorInfo, axisSupportedTypes, descriptorName);
1683 
1684  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1685  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1686 }
1687 
1689 {
1690  const std::string descriptorName{"FakeQuantizationQueueDescriptor"};
1691 
1692  ValidateNumInputs(workloadInfo, descriptorName, 1);
1693  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1694 
1695  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1696  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1697 
1698  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 2, "input");
1699  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1700 
1701  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1702 
1704  {
1705  throw InvalidArgumentException(descriptorName + ": min cannot be greater than max");
1706  }
1707 }
1708 
1710 {
1711  const std::string descriptorName{"InstanceNormalizationQueueDescriptor"};
1712 
1713  ValidateNumInputs(workloadInfo, descriptorName, 1);
1714  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1715 
1716  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1717  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1718 
1719  if (inputTensorInfo.GetNumDimensions() > 4)
1720  {
1721  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1722  }
1723 
1724  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1725 
1726  // Check the supported data types
1727  std::vector<DataType> supportedTypes =
1728  {
1732  };
1733 
1734  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1735  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1736 }
1737 
1739 {
1740  const std::string descriptorName{"L2NormalizationQueueDescriptor"};
1741 
1742  ValidateNumInputs(workloadInfo, descriptorName, 1);
1743  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1744 
1745  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1746  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1747 
1748  if (inputTensorInfo.GetNumDimensions() > 4)
1749  {
1750  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1751  }
1752 
1753  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1754 
1755  // Check the supported data types
1756  std::vector<DataType> supportedTypes =
1757  {
1764  };
1765 
1766  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1767  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1768 }
1769 
1770 void LogSoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1771 {
1772  const std::string descriptorName{"LogSoftmaxQueueDescriptor"};
1773 
1774  ValidateNumInputs(workloadInfo, descriptorName, 1);
1775  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1776 
1777  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1778  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1779 
1780  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1781 
1782  std::vector<DataType> supportedTypes =
1783  {
1789  };
1790 
1791  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1792  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1793 }
1794 
1795 void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1796 {
1797  const std::string descriptorName{"ConstantQueueDescriptor"};
1798 
1799  ValidateNumInputs(workloadInfo, descriptorName, 0);
1800  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1801 
1802  if (!m_LayerOutput)
1803  {
1804  throw InvalidArgumentException(descriptorName + ": No const input specified.");
1805  }
1806 
1807  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1808  ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(), outputTensorInfo, descriptorName, "constant", "output");
1809 
1810  // Check the supported data types
1811  std::vector<DataType> supportedTypes =
1812  {
1822  };
1823 
1824  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1825 }
1826 
1827 void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1828 {
1829  const std::string descriptorName{"ReshapeQueueDescriptor"};
1830 
1831  ValidateNumInputs(workloadInfo, descriptorName, 1);
1832  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1833 
1834  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1835  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1836 
1837  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1838 
1839  // Check the supported data types
1840  std::vector<DataType> supportedTypes =
1841  {
1850  };
1851 
1852  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1853  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1854 }
1855 
1857 {
1858  const std::string descriptorName{"SpaceToBatchNdQueueDescriptor"};
1859 
1860  ValidateNumInputs(workloadInfo, descriptorName, 1);
1861  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1862 
1863  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1864  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1865 
1866  if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
1867  {
1868  throw InvalidArgumentException(descriptorName + ": Pad List must contain the same number of "
1869  "dimensions as Block Shape.");
1870  }
1871 
1872  if (m_Parameters.m_BlockShape.size() == 2)
1873  {
1874  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1875  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1876  }
1877  else if (m_Parameters.m_BlockShape.size() == 1)
1878  {
1879  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 3, "input");
1880  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 3, "output");
1881  }
1882  else
1883  {
1884  throw InvalidArgumentException(descriptorName + ": Invalid Block and Crops size.");
1885  }
1886 
1887  // Check input + padding and output have the same number of elements
1888  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1889  const unsigned int inputHeight = inputTensorInfo.GetShape()[dimensionIndices.GetHeightIndex()] +
1890  m_Parameters.m_PadList[0].first + m_Parameters.m_PadList[0].second;
1891  const unsigned int inputWidth = (inputTensorInfo.GetNumDimensions() == 3) ? 1 :
1892  inputTensorInfo.GetShape()[dimensionIndices.GetWidthIndex()] +
1893  m_Parameters.m_PadList[1].first + m_Parameters.m_PadList[1].second;
1894 
1895  const int channelsIndex_int = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : -1;
1896  const unsigned int channelsIndex = channelsIndex_int < 0 ?
1897  static_cast<unsigned int>(channelsIndex_int) + inputTensorInfo.GetNumDimensions()
1898  : static_cast<unsigned int>(channelsIndex_int);
1899 
1900  const unsigned int numInputElements = inputTensorInfo.GetShape()[0] *
1901  inputHeight *
1902  inputWidth *
1903  inputTensorInfo.GetShape()[channelsIndex];
1904 
1905  if (outputTensorInfo.GetNumElements() != numInputElements)
1906  {
1907  throw InvalidArgumentException(descriptorName + ": Input tensor has " +
1908  to_string(numInputElements) + " after padding but output tensor has " +
1909  to_string(outputTensorInfo.GetNumElements()) + " elements.");
1910  }
1911 
1912  // In a 4D tensor, there will be 2 spatialDimensions (H and W), and the for loop will run twice.
1913  // In a 3D tensor, there will be 1 spatialDimensions, and the for loop will run once.
1914  unsigned int firstSpatialDimension = m_Parameters.m_DataLayout == DataLayout::NCHW ? 2 : 1;
1915  for (unsigned int i = 0; i < m_Parameters.m_BlockShape.size(); ++i)
1916  {
1917  unsigned int spatialDimension = firstSpatialDimension + i;
1918  auto inputSize = inputTensorInfo.GetShape()[spatialDimension] +
1919  m_Parameters.m_PadList[i].first +
1920  m_Parameters.m_PadList[i].second;
1921  if (inputSize % m_Parameters.m_BlockShape[i] != 0)
1922  {
1923  throw InvalidArgumentException(descriptorName + ": Input dimension size after padding must be "
1924  "divisible by Block Shape in dimension: " + to_string(spatialDimension) + ".");
1925  }
1926  }
1927 
1928  std::vector<DataType> supportedTypes =
1929  {
1936  };
1937 
1938  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1939  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1940 }
1941 
1943 {
1944  const std::string descriptorName{"SpaceToDepthQueueDescriptor"};
1945 
1946  ValidateNumInputs(workloadInfo, descriptorName, 1);
1947  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1948 
1949  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1950  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1951 
1952  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1953  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1954 
1955  std::vector<DataType> supportedTypes =
1956  {
1965  };
1966 
1967  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1968  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1969 
1970  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1971 
1972  if (m_Parameters.m_BlockSize == 0)
1973  {
1974  throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
1975  }
1976 
1977  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1978  const unsigned int wIndex = dimensionIndices.GetWidthIndex();
1979  const unsigned int hIndex = dimensionIndices.GetHeightIndex();
1980  const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
1981 
1982  const TensorShape& inputShape = inputTensorInfo.GetShape();
1983  if (inputShape[hIndex] % m_Parameters.m_BlockSize != 0 || inputShape[wIndex] % m_Parameters.m_BlockSize != 0)
1984  {
1985  throw InvalidArgumentException(descriptorName + ": Input shape must be divisible "
1986  "by block size in all spatial dimensions");
1987  }
1988 
1989  const TensorShape& outputShape = outputTensorInfo.GetShape();
1990  if (outputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
1991  {
1992  throw InvalidArgumentException(descriptorName + ": The depth of the output tensor"
1993  "must be divisible by the square of block size." );
1994  }
1995 }
1996 
1997 void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1998 {
1999  const std::string descriptorName{"FloorQueueDescriptor"};
2000 
2001  ValidateNumInputs(workloadInfo, descriptorName, 1);
2002  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2003 
2004  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2005  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2006 
2007  std::vector<DataType> supportedTypes =
2008  {
2013  };
2014 
2015  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2016  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2017  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2018  ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2019 }
2020 
2021 void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2022 {
2023  // ported from android/ml/nn/common/operations/LSTM.cpp CheckInputTensorDimensions()
2024 
2025  const std::string descriptorName{"LstmQueueDescriptor"};
2026 
2027  // check dimensions of all inputs and outputs
2028  if (workloadInfo.m_InputTensorInfos.size() != 3)
2029  {
2030  throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
2031  }
2032  if (workloadInfo.m_OutputTensorInfos.size() != 4)
2033  {
2034  throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
2035  }
2036 
2037  std::vector<DataType> supportedTypes =
2038  {
2043  };
2044 
2045  // check for supported type of one input and match them with all the other input and output
2046  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
2047 
2048  // type matches all other inputs
2049  for (uint32_t i = 1u; i < workloadInfo.m_InputTensorInfos.size(); ++i)
2050  {
2051  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
2052  workloadInfo.m_InputTensorInfos[i],
2053  descriptorName,
2054  "input_0",
2055  "input_" + std::to_string(i));
2056  }
2057  // type matches all other outputs
2058  for (uint32_t i = 0u; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
2059  {
2060  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
2061  workloadInfo.m_OutputTensorInfos[i],
2062  "LstmQueueDescriptor",
2063  "input_0",
2064  "output_" + std::to_string(i));
2065  }
2066 
2067  // Making sure clipping parameters have valid values.
2068  // == 0 means no clipping
2069  // > 0 means clipping
2070  if (m_Parameters.m_ClippingThresCell < 0.0f)
2071  {
2072  throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
2073  }
2074  if (m_Parameters.m_ClippingThresProj < 0.0f)
2075  {
2076  throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
2077  }
2078 
2079  // Inferring batch size, number of outputs and number of cells from the inputs.
2080  const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[1];
2081  const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
2082  ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
2083  const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
2084  ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
2085  const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
2086 
2087  // input tensor
2088  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 2, (n_batch * n_input),
2089  descriptorName + " input_0");
2090  // outputStateInTensor
2091  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
2092  descriptorName + " input_1");
2093  // outputStateInTensor
2094  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
2095  descriptorName + " input_2");
2096  // scratchBufferTensor
2097  unsigned int scratchBufferSize = m_Parameters.m_CifgEnabled ? n_cell * 3 : n_cell * 4;
2098  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[0], 2, (n_batch * scratchBufferSize),
2099  descriptorName + " output_0");
2100  // outputStateOutTensor
2101  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[1], 2, (n_batch * n_output),
2102  descriptorName + " output_1");
2103  // cellStateOutTensor
2104  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 2, (n_batch * n_cell),
2105  descriptorName + " output_2");
2106  // outputTensor
2107  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[3], 2, (n_batch * n_output),
2108  descriptorName + " output_3");
2109 
2110  // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
2111  if ( m_InputToInputWeights )
2112  {
2114  (n_cell * n_input), "InputLayerNormWeights");
2115  }
2116 
2117  ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
2119  (n_cell * n_input), "InputToForgetWeights");
2120 
2121  ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
2123  (n_cell * n_input), "InputToCellWeights");
2124 
2126  {
2128  (n_cell * n_output), "RecurrentToInputWeights");
2129  }
2130 
2131  ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
2133  (n_cell * n_output), "RecurrentToForgetWeights");
2134 
2135  ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
2137  (n_cell * n_output), "RecurrentToCellWeights");
2138 
2139  // Make sure the input-gate's parameters are either both present (regular
2140  // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
2141  bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
2145  if (!cifg_weights_all_or_none)
2146  {
2147  throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
2148  "RecurrentToInputWeights must either both be present (regular LSTM) "
2149  "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
2150  "accordingly.");
2151  }
2152 
2153  if ( m_CellToInputWeights )
2154  {
2156  n_cell, "CellToInputWeights");
2157  }
2158  if ( m_CellToForgetWeights )
2159  {
2161  n_cell, "CellToForgetWeights");
2162  }
2163  if ( m_CellToOutputWeights )
2164  {
2166  n_cell, "CellToOutputWeights");
2167  }
2168 
2169  // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
2170  bool peephole_weights_all_or_none =
2175  if (!peephole_weights_all_or_none)
2176  {
2177  throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
2178  }
2179 
2180  // Make sure the input gate bias is present only when not a CIFG-LSTM.
2182  {
2183  if (m_InputGateBias)
2184  {
2185  throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
2186  }
2187  }
2188  else
2189  {
2190  if (!m_InputGateBias)
2191  {
2192  throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
2193  "must be present.");
2194  }
2196  n_cell, "InputGateBias");
2197  }
2198 
2199  ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
2200  ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
2201 
2202  ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
2203  ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
2204 
2205  ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
2206  ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
2207 
2208  if (m_ProjectionWeights)
2209  {
2211  (n_cell * n_output), "ProjectionWeights");
2212  }
2213  if (m_ProjectionBias)
2214  {
2215  ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
2216  }
2217 
2218  // Making sure the projection tensors are consistent:
2219  // 1) If projection weight is not present, then projection bias should not be
2220  // present.
2221  // 2) If projection weight is present, then projection bias is optional.
2222  bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
2228  if (!projecton_tensors_consistent)
2229  {
2230  throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
2231  }
2232 
2233  // The four layer normalization weights either all have values or none of them have values. Additionally, if
2234  // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
2235  // either all have values or none of them have values. Layer normalization is used when the values of all the
2236  // layer normalization weights are present
2238  {
2239  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
2240  }
2242  {
2243  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2244  }
2246  {
2247  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2248  }
2250  {
2251  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2252  }
2253 
2255  {
2257  {
2259  {
2260  throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
2261  "disabled but InputLayerNormWeights are not present");
2262  }
2264  1, n_cell, "InputLayerNormWeights");
2265  }
2266  else if (m_InputLayerNormWeights)
2267  {
2268  throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
2269  "enabled");
2270  }
2271 
2272  ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
2273  "ForgetLayerNormWeights");
2274  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2275 
2276  ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
2277  "OutputLayerNormWeights");
2278  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2279 
2280  ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
2281  "CellLayerNormWeights");
2282  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2283  }
2285  {
2286  throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
2287  "normalisation weights are present.");
2288  }
2289 }
2290 
2292 {
2293  const std::string descriptorName{"ConvertFp32ToFp16QueueDescriptor"};
2294 
2295  ValidateNumInputs(workloadInfo, descriptorName, 1);
2296  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2297 
2298  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2299  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2300 
2301  if (inputTensorInfo.GetDataType() != DataType::Float32)
2302  {
2303  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32.");
2304  }
2305 
2306  if (outputTensorInfo.GetDataType() != DataType::Float16)
2307  {
2308  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float16.");
2309  }
2310 
2311  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2312 }
2313 
2315 {
2316  const std::string descriptorName{"ConvertFp16ToFp32QueueDescriptor"};
2317 
2318  ValidateNumInputs(workloadInfo, descriptorName, 1);
2319  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2320 
2321  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2322  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2323 
2324  if (inputTensorInfo.GetDataType() != DataType::Float16)
2325  {
2326  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float16.");
2327  }
2328 
2329  if (outputTensorInfo.GetDataType() != DataType::Float32)
2330  {
2331  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32.");
2332  }
2333 
2334  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2335 }
2336 
2337 void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2338 {
2339  const std::string descriptorName{"DivisionQueueDescriptor"};
2340 
2341  ValidateNumInputs(workloadInfo, descriptorName, 2);
2342  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2343 
2344  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2345  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2346  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2347 
2348  std::vector<DataType> supportedTypes =
2349  {
2357  };
2358 
2359  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2360  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2361  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2362 
2363  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2364  inputTensorInfo1,
2365  outputTensorInfo,
2366  descriptorName,
2367  "input_0",
2368  "input_1");
2369 }
2370 
2372 {
2373  const std::string descriptorName{"SubtractionQueueDescriptor"};
2374 
2375  ValidateNumInputs(workloadInfo, descriptorName, 2);
2376  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2377 
2378  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2379  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2380  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2381 
2382  std::vector<DataType> supportedTypes =
2383  {
2391  };
2392 
2393  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2394  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2395  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2396 
2397  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2398  inputTensorInfo1,
2399  outputTensorInfo,
2400  descriptorName,
2401  "input_0",
2402  "input_1");
2403 }
2404 
2405 void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2406 {
2407  const std::string descriptorName{"MaximumQueueDescriptor"};
2408 
2409  ValidateNumInputs(workloadInfo, descriptorName, 2);
2410  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2411 
2412  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2413  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2414  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2415 
2416  std::vector<DataType> supportedTypes =
2417  {
2425  };
2426 
2427  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2428  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2429  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2430 
2431  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2432  inputTensorInfo1,
2433  outputTensorInfo,
2434  descriptorName,
2435  "input_0",
2436  "input_1");
2437 }
2438 
2439 void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2440 {
2441  const std::string descriptorName{"MeanQueueDescriptor"};
2442 
2443  ValidateNumInputs(workloadInfo, descriptorName, 1);
2444  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2445 
2446  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2447  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2448 
2449  std::vector<DataType> supportedTypes =
2450  {
2458  };
2459 
2460  // First check if input tensor data type is supported, then
2461  // check if this data type matches the output tensor data type
2462  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2463  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2464 
2466  {
2467  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2468  }
2469  else if (m_Parameters.m_Axis.empty())
2470  {
2471  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
2472  }
2473  else
2474  {
2475  unsigned int outputDim =
2476  inputTensorInfo.GetNumDimensions() - armnn::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
2477  ValidateTensorNumDimensions(outputTensorInfo,
2478  descriptorName,
2479  outputDim > 0 ? outputDim : 1,
2480  "output");
2481  }
2482 }
2483 
2484 void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2485 {
2486  const std::string descriptorName{"PadQueueDescriptor"};
2487 
2488  ValidateNumInputs(workloadInfo, descriptorName, 1);
2489  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2490 
2491  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2492  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2493 
2494  // input and output should have the same number of dimensions
2495  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2496 
2497  // there should be entry in the pad list for each dimension in the input tensor
2498  if (m_Parameters.m_PadList.size() != inputTensorInfo.GetNumDimensions()) {
2499  throw InvalidArgumentException(descriptorName + ":Pad List should contain the same number of entries "
2500  "as there are dimensions in the input tensor that is " +
2501  std::to_string(inputTensorInfo.GetNumDimensions()) + " entries " +
2502  " not " + std::to_string(m_Parameters.m_PadList.size()) + " entries.");
2503  }
2504 }
2505 
2506 void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2507 {
2508  const std::string descriptorName{"QuantizeQueueDescriptor"};
2509 
2510  ValidateNumInputs(workloadInfo, descriptorName, 1);
2511  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2512 
2513  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2514  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2515 
2516  std::vector<DataType> supportedTypes =
2517  {
2525  };
2526 
2527  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2528 
2529  if (!IsQuantizedType(outputTensorInfo.GetDataType()))
2530  {
2531  throw InvalidArgumentException(descriptorName + ": Output of quantized layer must be quantized type.");
2532  }
2533 }
2534 
2536 {
2537  const std::string descriptorName{"BatchToSpaceNdQueueDescriptor"};
2538 
2539  ValidateNumInputs(workloadInfo, descriptorName, 1);
2540  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2541 
2542  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2543  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2544 
2545  if (m_Parameters.m_BlockShape.size() != m_Parameters.m_Crops.size())
2546  {
2547  throw InvalidArgumentException(descriptorName + ": Crops must contain the same number of "
2548  "dimensions as Block Shape.");
2549  }
2550 
2551  if (m_Parameters.m_BlockShape.size() == 2)
2552  {
2553  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
2554  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
2555  }
2556  else if (m_Parameters.m_BlockShape.size() == 1)
2557  {
2558  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 3, "input");
2559  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 3, "output");
2560  }
2561  else
2562  {
2563  throw InvalidArgumentException(descriptorName + ": Invalid Block and Crops size.");
2564  }
2565 
2566  // In a 4D tensor, there will be 2 spatialDimensions (H and W), and the for loop will run twice.
2567  // In a 3D tensor, there will be 1 spatialDimensions, and the for loop will run once.
2568  unsigned int firstSpatialDimension = m_Parameters.m_DataLayout == DataLayout::NCHW ? 2 : 1;
2569  for (unsigned int i = 0; i < m_Parameters.m_BlockShape.size(); ++i)
2570  {
2571  unsigned int spatialDimension = firstSpatialDimension + i;
2572  unsigned int cropSize = m_Parameters.m_Crops[i].first + m_Parameters.m_Crops[i].second;
2573  unsigned int outputSize = inputTensorInfo.GetShape()[spatialDimension] * m_Parameters.m_BlockShape[i];
2574  if (cropSize > outputSize)
2575  {
2576  throw InvalidArgumentException(descriptorName + ": CropSize must be less than or equal to the uncropped"
2577  "outputSize in dimension: " + to_string(spatialDimension) + ".");
2578  }
2579  }
2580 
2581  std::vector<DataType> supportedTypes =
2582  {
2589  };
2590 
2591  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2592  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2593 }
2594 
2596 {
2597  const std::string descriptorName{"StridedSliceQueueDescriptor"};
2598 
2599  ValidateNumInputs(workloadInfo, descriptorName, 1);
2600  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2601 
2602  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2603  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2604 
2605  std::vector<DataType> supportedTypes =
2606  {
2614  };
2615 
2616  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2617  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2618 
2619  ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2620 
2621  const uint32_t rank = inputTensorInfo.GetNumDimensions();
2622  if (rank > 4)
2623  {
2624  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
2625  }
2626 
2627  // Begin, End & Stride length must be of rank(input0)
2628  if (m_Parameters.m_Begin.size() != rank)
2629  {
2630  throw InvalidArgumentException(descriptorName + ": Begin length must be of rank " + std::to_string(rank));
2631  }
2632 
2633  if (m_Parameters.m_End.size() != rank)
2634  {
2635  throw InvalidArgumentException(descriptorName + ": End length must be of rank " + std::to_string(rank));
2636  }
2637 
2638  if (m_Parameters.m_Stride.size() != rank)
2639  {
2640  throw InvalidArgumentException(descriptorName + ": Stride length must be of rank " + std::to_string(rank));
2641  }
2642 
2643  // Stride entries must be non-zero
2644  for (auto& stride : m_Parameters.m_Stride)
2645  {
2646  if (stride == 0)
2647  {
2648  throw InvalidArgumentException(descriptorName + ": Stride entries must be non-zero.");
2649  }
2650  }
2651 }
2652 
2653 void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2654 {
2655  const std::string descriptorName{"MinimumQueueDescriptor"};
2656 
2657  ValidateNumInputs(workloadInfo, descriptorName, 2);
2658  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2659 
2660  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2661  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2662  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2663 
2664  std::vector<DataType> supportedTypes =
2665  {
2673  };
2674 
2675  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2676  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2677  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2678 
2679  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2680  inputTensorInfo1,
2681  outputTensorInfo,
2682  descriptorName,
2683  "input_0",
2684  "input_1");
2685 }
2686 
2687 void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2688 {
2689  const std::string descriptorName{"DebugQueueDescriptor"};
2690 
2691  ValidateNumInputs(workloadInfo, descriptorName, 1);
2692  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2693 }
2694 
2695 void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2696 {
2697  const std::string descriptorName{"EqualQueueDescriptor"};
2698 
2699  ValidateNumInputs(workloadInfo, descriptorName, 2);
2700  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2701 
2702  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2703  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2704  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2705 
2706  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2707  inputTensorInfo1,
2708  outputTensorInfo,
2709  descriptorName,
2710  "input_0",
2711  "input_1");
2712 
2713  if (outputTensorInfo.GetDataType() != DataType::Boolean)
2714  {
2715  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2716  }
2717 }
2718 
2719 void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2720 {
2721  const std::string descriptorName{"GreaterQueueDescriptor"};
2722 
2723  ValidateNumInputs(workloadInfo, descriptorName, 2);
2724  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2725 
2726  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2727  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2728  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2729 
2730  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2731  inputTensorInfo1,
2732  outputTensorInfo,
2733  descriptorName,
2734  "input_0",
2735  "input_1");
2736 
2737  if (outputTensorInfo.GetDataType() != DataType::Boolean)
2738  {
2739  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2740  }
2741 }
2742 
2743 void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2744 {
2745  const std::string descriptorName{"RsqrtQueueDescriptor"};
2746 
2747  ValidateNumInputs(workloadInfo, descriptorName, 1);
2748  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2749 
2750  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2751  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2752 
2753  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2754 
2755  std::vector<DataType> supportedTypes =
2756  {
2763  };
2764 
2765  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2766  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2767 }
2768 
2769 void GatherNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2770 {
2771  const std::string descriptorName{"GatherNdQueueDescriptor"};
2772 
2773  ValidateNumInputs(workloadInfo, descriptorName, 2);
2774  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2775 
2776  const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1];
2777  if (indicesTensorInfo.GetDataType() != DataType::Signed32)
2778  {
2779  throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32.");
2780  }
2781 
2782  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2783  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2784 
2785  std::vector<DataType> supportedTypes =
2786  {
2795  };
2796 
2797  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2798 
2799  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2800 
2801  unsigned int outputDim = outputTensorInfo.GetNumDimensions();
2802  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output");
2803 }
2804 
2805 void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2806 {
2807  const std::string descriptorName{"GatherQueueDescriptor"};
2808 
2809  ValidateNumInputs(workloadInfo, descriptorName, 2);
2810  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2811 
2812  const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1];
2813  if (indicesTensorInfo.GetDataType() != DataType::Signed32)
2814  {
2815  throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32.");
2816  }
2817 
2818  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2819  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2820 
2821  std::vector<DataType> supportedTypes =
2822  {
2831  };
2832 
2833  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2834 
2835  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2836 
2837  unsigned int outputDim = inputTensorInfo.GetNumDimensions() + indicesTensorInfo.GetNumDimensions() - 1;
2838  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output");
2839 }
2840 
2842 {
2843  const std::string& descriptorName{"DetectionPostProcessQueueDescriptor"};
2844 
2845  ValidateNumInputs(workloadInfo, descriptorName, 2);
2846 
2847  if (workloadInfo.m_OutputTensorInfos.size() != 4)
2848  {
2849  throw InvalidArgumentException(descriptorName + ": Requires exactly four outputs. " +
2850  to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
2851  }
2852 
2853  if (m_Anchors == nullptr)
2854  {
2855  throw InvalidArgumentException(descriptorName + ": Anchors tensor descriptor is missing.");
2856  }
2857 
2858  const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
2859  const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
2860  const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
2861 
2862  const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
2863  const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
2864  const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
2865  const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
2866 
2867  ValidateTensorNumDimensions(boxEncodingsInfo, descriptorName, 3, "box encodings");
2868  ValidateTensorNumDimensions(scoresInfo, descriptorName, 3, "scores");
2869  ValidateTensorNumDimensions(anchorsInfo, descriptorName, 2, "anchors");
2870 
2871  const std::vector<DataType> supportedInputTypes =
2872  {
2879  };
2880 
2881  ValidateDataTypes(boxEncodingsInfo, supportedInputTypes, descriptorName);
2882  ValidateDataTypes(scoresInfo, supportedInputTypes, descriptorName);
2883  ValidateDataTypes(anchorsInfo, supportedInputTypes, descriptorName);
2884 
2885  ValidateTensorNumDimensions(detectionBoxesInfo, descriptorName, 3, "detection boxes");
2886  ValidateTensorNumDimensions(detectionScoresInfo, descriptorName, 2, "detection scores");
2887  ValidateTensorNumDimensions(detectionClassesInfo, descriptorName, 2, "detection classes");
2888  ValidateTensorNumDimensions(numDetectionsInfo, descriptorName, 1, "num detections");
2889 
2890  // NOTE: Output is always Float32 regardless of input type
2891  ValidateTensorDataType(detectionBoxesInfo, DataType::Float32, descriptorName, "detection boxes");
2892  ValidateTensorDataType(detectionScoresInfo, DataType::Float32, descriptorName, "detection scores");
2893  ValidateTensorDataType(detectionClassesInfo, DataType::Float32, descriptorName, "detection classes");
2894  ValidateTensorDataType(numDetectionsInfo, DataType::Float32, descriptorName, "num detections");
2895 
2897  {
2898  throw InvalidArgumentException(descriptorName + ": Intersection over union threshold "
2899  "must be positive and less than or equal to 1.");
2900  }
2901 
2902  if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
2903  {
2904  throw InvalidArgumentException(descriptorName + ": Number of classes with background "
2905  "should be equal to number of classes + 1.");
2906  }
2907 }
2908 
2909 void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2910 {
2911  const std::string& descriptorName{"DequantizeQueueDescriptor"};
2912 
2913  ValidateNumInputs(workloadInfo, descriptorName, 1);
2914  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2915 
2916  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2917  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2918 
2919  std::vector<DataType> inputSupportedTypes =
2920  {
2926  };
2927  ValidateDataTypes(inputTensorInfo, inputSupportedTypes, descriptorName);
2928 
2929  std::vector<DataType> outputSupportedTypes =
2930  {
2934  };
2935 
2936  ValidateDataTypes(outputTensorInfo, outputSupportedTypes, descriptorName);
2937 }
2938 
2939 void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2940 {
2941  const std::string& descriptorName{"MergeQueueDescriptor"};
2942 
2943  ValidateNumInputs(workloadInfo, descriptorName, 2);
2944  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2945 
2946  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2947  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2948  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2949 
2950  ValidateTensorShapesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2951  ValidateTensorShapesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2952 
2953  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2954  ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2955 }
2956 
2957 void ShapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2958 {
2959  const std::string& descriptorName{"ShapeQueueDescriptor"};
2960 
2961  ValidateNumInputs(workloadInfo, descriptorName, 1);
2962  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2963 
2964  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2965  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2966 
2967  std::vector<DataType> supportedTypes =
2968  {
2977  };
2978 
2979  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2980  ValidateDataTypes(outputTensorInfo, {DataType::Signed32}, descriptorName);
2981 }
2982 
2983 void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2984 {
2985  const std::string& descriptorName{"SwitchQueueDescriptor"};
2986 
2987  ValidateNumInputs(workloadInfo, descriptorName, 2);
2988  ValidateNumOutputs(workloadInfo, descriptorName, 2);
2989 
2990  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2991  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2992 
2993  const TensorInfo& outputTensorInfo0 = workloadInfo.m_OutputTensorInfos[0];
2994  const TensorInfo& outputTensorInfo1 = workloadInfo.m_OutputTensorInfos[1];
2995 
2996  std::vector<DataType> supportedTypes =
2997  {
3003  };
3004 
3005  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
3006  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
3007 
3008  ValidateDataTypes(outputTensorInfo0, supportedTypes, descriptorName);
3009  ValidateDataTypes(outputTensorInfo1, supportedTypes, descriptorName);
3010 
3011  ValidateTensorShapesMatch(inputTensorInfo0,
3012  outputTensorInfo0,
3013  descriptorName,
3014  "input_0",
3015  "output_0");
3016 
3017  ValidateTensorShapesMatch(inputTensorInfo0,
3018  outputTensorInfo1,
3019  descriptorName,
3020  "input_0",
3021  "output_1");
3022 }
3023 
3024 void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& /*workloadInfo*/) const
3025 {
3026  // This is internally generated, so it should not need validation.
3027 }
3028 
3029 void PreluQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3030 {
3031  const std::string& descriptorName{"PreluQueueDescriptor"};
3032 
3033  ValidateNumInputs(workloadInfo, descriptorName, 2);
3034  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3035 
3036  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3037  const TensorInfo& alphaTensorInfo = workloadInfo.m_InputTensorInfos[1];
3038  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3039 
3040  std::vector<DataType> supportedTypes
3041  {
3048  };
3049 
3050  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3051  ValidateDataTypes(alphaTensorInfo, supportedTypes, descriptorName);
3052 
3053  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
3054 
3055  ValidateTensorDataTypesMatch(inputTensorInfo, alphaTensorInfo, descriptorName, "input", "alpha");
3056  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "ouptut");
3057 
3058  ValidateBroadcastTensorShapesMatch(inputTensorInfo,
3059  alphaTensorInfo,
3060  outputTensorInfo,
3061  descriptorName,
3062  "input",
3063  "alpha");
3064 }
3065 
3067 {
3068  const std::string descriptorName{"TransposeConvolution2dQueueDescriptor"};
3069 
3070  ValidateNumInputs(workloadInfo, descriptorName, 1);
3071  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3072 
3073  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3074  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3075 
3076  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
3077  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
3078 
3079  ValidatePointer(m_Weight, descriptorName, "weight");
3080 
3081  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
3082  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
3083 
3084  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
3085 
3086  Optional<TensorInfo> optionalBiasTensorInfo;
3088  {
3089  ValidatePointer(m_Bias, descriptorName, "bias");
3090 
3091  optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
3092  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
3093 
3094  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
3095  ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
3096  }
3097 
3098  ValidatePerAxisQuantization(inputTensorInfo,
3099  outputTensorInfo,
3100  weightTensorInfo,
3101  optionalBiasTensorInfo,
3102  descriptorName);
3103 
3104  std::vector<DataType> supportedTypes =
3105  {
3112  };
3113 
3114  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3115  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3116 }
3117 
3118 void TransposeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3119 {
3120  const std::string descriptorName{"TransposeQueueDescriptor"};
3121 
3122  ValidateNumInputs(workloadInfo, descriptorName, 1);
3123  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3124 
3125  const PermutationVector& mapping = m_Parameters.m_DimMappings;
3126 
3127  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3128  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3129 
3130  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
3131  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
3132 
3133  for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
3134  {
3135  if (inputTensorInfo.GetShape()[mapping[i]] != outputTensorInfo.GetShape()[i])
3136  {
3137  throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(mapping[i]) +
3138  " (=" + to_string(inputTensorInfo.GetShape()[mapping[i]]) + ") " +
3139  "must match dst dimension " + to_string(i) +
3140  " (=" + to_string(outputTensorInfo.GetShape()[i]) + ")");
3141  }
3142  }
3143 
3144  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3145 }
3146 
3148 {
3149  const std::string descriptorName{"TransposeQueueDescriptor"};
3150 
3151  ValidateNumInputs(workloadInfo, descriptorName, 1);
3152  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3153 
3154  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3155  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3156 
3157  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3158 }
3159 
3160 void QLstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3161 {
3162  const std::string descriptorName{"QLstmQueueDescriptor"};
3163 
3164  // Validate number of inputs/outputs
3165  ValidateNumInputs(workloadInfo, descriptorName, 3);
3166  ValidateNumOutputs(workloadInfo, descriptorName, 3);
3167 
3168  // Input/output tensor info
3169  auto inputInfo = workloadInfo.m_InputTensorInfos[0];
3170  auto outputStateInInfo = workloadInfo.m_InputTensorInfos[1];
3171  auto cellStateInInfo = workloadInfo.m_InputTensorInfos[2];
3172 
3173  auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
3174  auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
3175  auto outputInfo = workloadInfo.m_OutputTensorInfos[2];
3176 
3177  // Supported types for various tensors in QLSTM
3178  std::vector<DataType> inputOutputSupportedTypes =
3179  {
3181  };
3182 
3183  std::vector<DataType> cellStateSupportedTypes =
3184  {
3186  };
3187 
3188  std::vector<DataType> weightsSupportedTypes =
3189  {
3191  };
3192 
3193  std::vector<DataType> layerNormPeepholeWeightsSupportedTypes =
3194  {
3196  };
3197 
3198  std::vector<DataType> biasSupportedTypes =
3199  {
3201  };
3202 
3203  // Validate types of input/output tensors
3204  ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3205  ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3206  ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3207 
3208  ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3209  ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3210  ValidateDataTypes(outputInfo, inputOutputSupportedTypes, descriptorName);
3211 
3212  // Validate matching types of input/output tensors
3213  ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3214  ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3215  "outputStateIn", "outputStateOut");
3216  ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3217 
3218  // Infer number of batches, number of units, input size and output size from tensor dimensions
3219  const uint32_t numBatches = inputInfo.GetShape()[0];
3220  const uint32_t inputSize = inputInfo.GetShape()[1];
3221  const uint32_t outputSize = outputStateInInfo.GetShape()[1];
3222  const uint32_t numUnits = cellStateInInfo.GetShape()[1];
3223 
3224  // Validate number of dimensions and number of elements for input/output tensors
3225  ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3226  ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3227  ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * numUnits), descriptorName + " cellStateIn");
3228 
3229  ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3230  ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * numUnits), descriptorName + " cellStateOut");
3231  ValidateTensorNumDimNumElem(outputInfo, 2, (numBatches * outputSize), descriptorName + " output");
3232 
3233  // Validate number of dimensions and number of elements for MANDATORY weight tensors
3234  ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3235  auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3236  ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (numUnits * inputSize), " InputToForgetWeights");
3237 
3238  ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3239  auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3240  ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (numUnits * inputSize), " InputToCellWeights");
3241 
3242  ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3243  auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3244  ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (numUnits * inputSize), " InputToOutputWeights");
3245 
3246  ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3247  auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3248  ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (numUnits * outputSize),
3249  " RecurrentToForgetWeights");
3250 
3251  ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3252  auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3253  ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3254 
3255  ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3256  auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3257  ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3258 
3259  // Validate data types for MANDATORY weights tensors (all should match each other)
3260  ValidateDataTypes(inputToForgetWeightsInfo, weightsSupportedTypes, descriptorName);
3261 
3262  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToCellWeightsInfo, descriptorName,
3263  "inputToForgetWeights", "inputToCellWeights");
3264  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3265  "inputToForgetWeights", "inputToOutputWeights");
3266 
3267  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3268  "inputToForgetWeights", "recurrentToForgeteights");
3269  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3270  "inputToForgetWeights", "recurrentToCellWeights");
3271  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3272  "inputToForgetWeights", "recurrentToOutputWeights");
3273 
3274  // Validate number of dimensions and number of elements for MANDATORY bias tensors
3275  ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3276  auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3277  ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, numUnits, " ForgetGateBias");
3278 
3279  ValidatePointer(m_CellBias, descriptorName, "CellBias");
3280  auto cellBiasInfo = m_CellBias->GetTensorInfo();
3281  ValidateTensorNumDimNumElem(cellBiasInfo, 1, numUnits, " CellBias");
3282 
3283  ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3284  auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3285  ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, numUnits, " OutputGateBias");
3286 
3287  // Validate data types for MANDATORY bias tensors
3288  ValidateDataTypes(forgetGateBiasInfo, biasSupportedTypes, descriptorName);
3289 
3290  ValidateTensorDataTypesMatch(forgetGateBiasInfo, cellBiasInfo, descriptorName,
3291  "forgetGateBias", "cellBias");
3292  ValidateTensorDataTypesMatch(forgetGateBiasInfo, outputGateBiasInfo, descriptorName,
3293  "forgetGateBias", "outputGateBias");
3294 
3295  // Validate OPTIONAL params: CIFG (inputToInputWeights, recurrentToInputWeights, inputGateBias)
3296  const bool allCifgParamsPresentOrNot = ((m_InputToInputWeights && m_RecurrentToInputWeights && m_InputGateBias &&
3300 
3301  if (!allCifgParamsPresentOrNot)
3302  {
3303  throw InvalidArgumentException(descriptorName +
3304  ": InputToInputWeights, RecurrentToInputWeights and InputGateBias must either all be present "
3305  "(CIFG disabled) or not be present at all (CIFG enabled). m_Parameters.m_CifgEnabled should be "
3306  "set appropriately.");
3307  }
3308 
3310  {
3311  // Validate number of dimensions and number of elements
3312  auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3313  ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (numUnits * inputSize), " InputToInputWeights");
3314 
3315  auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3316  ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (numUnits * outputSize),
3317  " RecurrentToInputWeights");
3318 
3319  auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3320  ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, numUnits, " InputGateBias");
3321 
3322  // Validate data types
3323  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToInputWeightsInfo, descriptorName,
3324  "inputToForgetWeights", "inputToInputWeights");
3325  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3326  "inputToForgetWeights", "recurrentToInputWeights");
3327  ValidateTensorDataTypesMatch(forgetGateBiasInfo, inputGateBiasInfo, descriptorName,
3328  "forgetGateBias", "inputGateBias");
3329  }
3330 
3331  // Validate OPTIONAL params: Peephole (cellToInputWeights, cellToForgetWeights, cellToOutputWeights)
3332  bool allPeepholeWeightsPresentOrNot =
3337 
3338  if (!allPeepholeWeightsPresentOrNot)
3339  {
3340  throw InvalidArgumentException(descriptorName +
3341  ": CellToInputWeights, CellToForgetWeights and CellToOutputWeights should all be present (Peephole "
3342  "enabled) or not be present at all (Peephole disabled). CellToInputWeights should only be present "
3343  "when Peephole is enabled and CIFG is disabled. m_Parameters.m_PeepholeEnabled should be set "
3344  "appropriately.");
3345  }
3346 
3348  {
3349  auto cellToForgetWeightsInfo = m_CellToForgetWeights->GetTensorInfo();
3350  ValidateTensorNumDimNumElem(cellToForgetWeightsInfo, 1, numUnits, " cellToForgetWeights");
3351  ValidateDataTypes(cellToForgetWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3352 
3353  auto cellToOutputWeightsInfo = m_CellToOutputWeights->GetTensorInfo();
3354  ValidateTensorNumDimNumElem(cellToOutputWeightsInfo, 1, numUnits, " cellToOutputWeights");
3355  ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToOutputWeightsInfo, descriptorName,
3356  "cellToForgetWeight", "cellToOutputWeights");
3357 
3359  {
3360  auto cellToInputWeightsInfo = m_CellToInputWeights->GetTensorInfo();
3361  ValidateTensorNumDimNumElem(cellToInputWeightsInfo, 1, numUnits, " cellToInputWeights");
3362  ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToInputWeightsInfo, descriptorName,
3363  "cellToForgetWeights", "cellToInputWeights");
3364  }
3365  }
3366 
3367  // Validate OPTIONAL params: Layer Norm Weights
3368  bool allLayerNormWeightsPresentOrNot =
3373 
3374  if (!allLayerNormWeightsPresentOrNot)
3375  {
3376  throw InvalidArgumentException(descriptorName +
3377  ": InputLayerNormWeights, ForgetLayerNormWeights, m_OutputLayerNormWeights "
3378  "and CellLayerNormWeights should all be present (Layer Norm enabled) or not "
3379  "be present at all (Layer Norm disabled). InputLayerNormWeights should "
3380  "only be present when Layer Norm is enabled and CIFG is disabled. "
3381  "m_Parameters.m_LayerNormEnabled should be set appropriately.");
3382  }
3383 
3385  {
3386  auto forgetLayerNormWeightsInfo = m_ForgetLayerNormWeights->GetTensorInfo();
3387  ValidateTensorNumDimNumElem(forgetLayerNormWeightsInfo, 1, numUnits, " forgetLayerNormWeights");
3388  ValidateDataTypes(forgetLayerNormWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3389 
3390  auto cellLayerNormWeightsInfo = m_CellLayerNormWeights->GetTensorInfo();
3391  ValidateTensorNumDimNumElem(cellLayerNormWeightsInfo, 1, numUnits, " cellLayerNormWeights");
3392  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, cellLayerNormWeightsInfo, descriptorName,
3393  "forgetLayerNormWeights", "cellLayerNormWeights");
3394 
3395  auto outputLayerNormWeightsInfo = m_OutputLayerNormWeights->GetTensorInfo();
3396  ValidateTensorNumDimNumElem(outputLayerNormWeightsInfo, 1, numUnits, " outputLayerNormWeights");
3397  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, outputLayerNormWeightsInfo, descriptorName,
3398  "forgetLayerNormWeights", "outputLayerNormWeights");
3399 
3401  {
3402  auto inputLayerNormWeightsInfo = m_InputLayerNormWeights->GetTensorInfo();
3403  ValidateTensorNumDimNumElem(inputLayerNormWeightsInfo, 1, numUnits, " inputLayerNormWeights");
3404  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, inputLayerNormWeightsInfo, descriptorName,
3405  "forgetLayerNormWeights", "inputLayerNormWeights");
3406  }
3407  }
3408 
3409  // Validate OPTIONAL params: Projection (projectionWeights, projectionBias)
3410  bool correctProjectionTensorsPresent =
3414 
3415  if (!correctProjectionTensorsPresent)
3416  {
3417  throw InvalidArgumentException(descriptorName +
3418  ": If projection is enabled, ProjectionWeights should be present and "
3419  "ProjectionBias is optional. If projection is disabled, neither "
3420  "ProjectionWeights nor ProjectionBias should be present.");
3421  }
3422 
3424  {
3425  auto projectionWeightsInfo = m_ProjectionWeights->GetTensorInfo();
3426  ValidateTensorNumDimNumElem(projectionWeightsInfo, 2, (numUnits * outputSize), "ProjectionWeights");
3427  ValidateDataTypes(projectionWeightsInfo, weightsSupportedTypes, descriptorName);
3428 
3429  if (m_ProjectionBias)
3430  {
3431  auto projectionBiasInfo = m_ProjectionBias->GetTensorInfo();
3432  ValidateTensorNumDimNumElem(projectionBiasInfo, 1, outputSize, "ProjectionBias");
3433  ValidateDataTypes(projectionBiasInfo, biasSupportedTypes, descriptorName);
3434  }
3435 
3436  }
3437  else if ((outputInfo.GetQuantizationScale() != m_Parameters.m_HiddenStateScale) &&
3439  throw InvalidArgumentException(descriptorName +
3440  ": If projection is disabled, output quantization info (scale, offset) "
3441  "should match HiddenStateScale and HiddenStateZeroPoint.");
3442  }
3443 
3444 }
3445 
3447 {
3448  const std::string descriptorName{"QuantizedLstmQueueDescriptor"};
3449 
3450  // Validate number of inputs/outputs
3451  ValidateNumInputs(workloadInfo, descriptorName, 3);
3452  ValidateNumOutputs(workloadInfo, descriptorName, 2);
3453 
3454  // Input/output tensor infos
3455  auto inputInfo = workloadInfo.m_InputTensorInfos[0];
3456  auto cellStateInInfo = workloadInfo.m_InputTensorInfos[1];
3457  auto outputStateInInfo = workloadInfo.m_InputTensorInfos[2];
3458 
3459  auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
3460  auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
3461 
3462  std::vector<DataType> inputOutputSupportedTypes =
3463  {
3465  };
3466 
3467  std::vector<DataType> cellStateSupportedTypes =
3468  {
3470  };
3471 
3472  std::vector<DataType> weightsSupportedTypes =
3473  {
3475  };
3476 
3477  std::vector<DataType> biasSupportedTypes =
3478  {
3480  };
3481 
3482  // Validate types of input/output tensors
3483  ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3484  ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3485  ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3486 
3487  ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3488  ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3489 
3490  // Validate matching types of input/output tensors
3491  ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3492  ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3493  "outputStateIn", "outputStateOut");
3494  ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3495 
3496  // Validate matching quantization info for input/output tensors
3497  ValidateTensorQuantizationSpace(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3498  ValidateTensorQuantizationSpace(inputInfo, outputStateOutInfo, descriptorName, "input", "outputStateOut");
3499  ValidateTensorQuantizationSpace(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3500 
3501  // Infer number of batches, input size and output size from tensor dimensions
3502  const uint32_t numBatches = inputInfo.GetShape()[0];
3503  const uint32_t inputSize = inputInfo.GetShape()[1];
3504  const uint32_t outputSize = cellStateInInfo.GetShape()[1];
3505 
3506  // Validate number of dimensions and number of elements for input/output tensors
3507  ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3508  ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * outputSize), descriptorName + " cellStateIn");
3509  ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3510  ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * outputSize), descriptorName + " cellStateOut");
3511  ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3512 
3513  // Validate number of dimensions and number of elements for weights tensors
3514  ValidatePointer(m_InputToInputWeights, descriptorName, "InputToInputWeights");
3515  auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3516  ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (outputSize * inputSize), " InputToInputWeights");
3517 
3518  ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3519  auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3520  ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (outputSize * inputSize), " InputToForgetWeights");
3521 
3522  ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3523  auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3524  ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (outputSize * inputSize), " InputToCellWeights");
3525 
3526  ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3527  auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3528  ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (outputSize * inputSize), " InputToOutputWeights");
3529 
3530  ValidatePointer(m_RecurrentToInputWeights, descriptorName, "RecurrentToInputWeights");
3531  auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3532  ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToInputWeights");
3533 
3534  ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3535  auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3536  ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (outputSize * outputSize),
3537  " RecurrentToForgetWeights");
3538 
3539  ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3540  auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3541  ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3542 
3543  ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3544  auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3545  ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3546 
3547  // Validate data types for weights tensors (all should match each other)
3548  ValidateDataTypes(inputToInputWeightsInfo, weightsSupportedTypes, descriptorName);
3549 
3550  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToForgetWeightsInfo, descriptorName,
3551  "inputToInputWeights", "inputToForgetWeights");
3552  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToCellWeightsInfo, descriptorName,
3553  "inputToInputWeights", "inputToCellWeights");
3554  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3555  "inputToInputWeights", "inputToOutputWeights");
3556 
3557  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3558  "inputToInputWeights", "recurrentToInputWeights");
3559  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3560  "inputToInputWeights", "recurrentToForgeteights");
3561  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3562  "inputToInputWeights", "recurrentToCellWeights");
3563  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3564  "inputToInputWeights", "recurrentToOutputWeights");
3565 
3566  // Validate matching quantization info for weight tensors (all should match each other)
3567  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToForgetWeightsInfo,
3568  descriptorName, "inputToInputWeights", "inputToForgetWeights");
3569  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToCellWeightsInfo,
3570  descriptorName, "inputToInputWeights", "inputToCellWeights");
3571  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToOutputWeightsInfo,
3572  descriptorName, "inputToInputWeights", "inputToOutputWeights");
3573 
3574  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToInputWeightsInfo,
3575  descriptorName, "inputToInputWeights", "recurrentToInputWeights");
3576  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToForgetWeightsInfo,
3577  descriptorName, "inputToInputWeights", "recurrentToForgetWeights");
3578  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToCellWeightsInfo,
3579  descriptorName, "inputToInputWeights", "recurrentToCellWeights");
3580  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToOutputWeightsInfo,
3581  descriptorName, "inputToInputWeights", "recurrentToOutputWeights");
3582 
3583  // Validate number of dimensions and number of elements in bias tensors
3584  ValidatePointer(m_InputGateBias, descriptorName, "InputGateBias");
3585  auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3586  ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, outputSize, " InputGateBias");
3587 
3588  ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3589  auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3590  ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, outputSize, " ForgetGateBias");
3591 
3592  ValidatePointer(m_CellBias, descriptorName, "CellBias");
3593  auto cellBiasInfo = m_CellBias->GetTensorInfo();
3594  ValidateTensorNumDimNumElem(cellBiasInfo, 1, outputSize, " CellBias");
3595 
3596  ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3597  auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3598  ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, outputSize, " OutputGateBias");
3599 
3600  // Validate data types for bias tensors (all should match each other)
3601  ValidateDataTypes(inputGateBiasInfo, biasSupportedTypes, descriptorName);
3602 
3603  ValidateTensorDataTypesMatch(inputGateBiasInfo, forgetGateBiasInfo, descriptorName,
3604  "inputGateBias", "forgetGateBias");
3605  ValidateTensorDataTypesMatch(inputGateBiasInfo, cellBiasInfo, descriptorName,
3606  "inputGateBias", "cellBias");
3607  ValidateTensorDataTypesMatch(inputGateBiasInfo, outputGateBiasInfo, descriptorName,
3608  "inputGateBias", "outputGateBias");
3609 
3610  // Validate bias tensor quantization info
3611  ValidateBiasTensorQuantization(inputGateBiasInfo, inputToInputWeightsInfo, descriptorName);
3612  ValidateBiasTensorQuantization(forgetGateBiasInfo, inputToInputWeightsInfo, descriptorName);
3613  ValidateBiasTensorQuantization(cellBiasInfo, inputToInputWeightsInfo, descriptorName);
3614  ValidateBiasTensorQuantization(outputGateBiasInfo, inputToInputWeightsInfo, descriptorName);
3615 }
3616 
3617 void AbsQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3618 {
3619  const std::string descriptorName{"AbsQueueDescriptor"};
3620 
3621  ValidateNumInputs(workloadInfo, descriptorName, 1);
3622  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3623 
3624  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3625  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3626 
3627  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3628 
3629  std::vector<DataType> supportedTypes =
3630  {
3638  };
3639 
3640  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3641  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3642 }
3643 
3644 void SliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3645 {
3646  const std::string descriptorName{"SliceQueueDescriptor"};
3647 
3648  ValidateNumInputs(workloadInfo, descriptorName, 1);
3649  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3650 
3651  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3652  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3653 
3654  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3655 
3656  const unsigned int rank = inputTensorInfo.GetNumDimensions();
3657  if (rank > 5)
3658  {
3659  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 5 are not supported.");
3660  }
3661 
3662  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, rank, "output");
3663 
3664  // Check if m_Begin and m_Size have the expected length
3665  if (m_Parameters.m_Begin.size() != rank)
3666  {
3667  throw InvalidArgumentException(descriptorName +
3668  ": Length of begin offset descriptor must equal rank " + std::to_string(rank));
3669  }
3670  if (m_Parameters.m_Size.size() != rank)
3671  {
3672  throw InvalidArgumentException(descriptorName +
3673  ": Length of size descriptor must equal rank " + std::to_string(rank));
3674  }
3675 
3676  // Check if the shape of the output tensor matches m_Size
3677  const TensorShape& outputShape = outputTensorInfo.GetShape();
3678  for (unsigned int i = 0u; i < rank; ++i)
3679  {
3680  if (m_Parameters.m_Size[i] != outputShape[i])
3681  {
3682  throw InvalidArgumentException(descriptorName + ": Size descriptor does not match output tensor.");
3683  }
3684  }
3685 
3686  // Check if the sum of begin offset and size in a given dimension
3687  // does not exceed the size of corresponding input
3688  const TensorShape& inputShape = inputTensorInfo.GetShape();
3689  for(unsigned int i = 0u; i < rank; ++i)
3690  {
3691  if (m_Parameters.m_Begin[i] + m_Parameters.m_Size[i] > inputShape[i])
3692  {
3693  throw InvalidArgumentException(descriptorName + ": Sum of begin offset and size for dimension " +
3694  std::to_string(i) + " exceeds input size.");
3695  }
3696  }
3697 }
3698 
3700 {
3701  const std::string descriptorName{"DepthToSpaceQueueDescriptor"};
3702 
3703  ValidateNumInputs(workloadInfo, descriptorName, 1);
3704  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3705 
3706  const TensorInfo& inputInfo = workloadInfo.m_InputTensorInfos[0];
3707  const TensorInfo& outputInfo = workloadInfo.m_OutputTensorInfos[0];
3708 
3709  ValidateTensorNumDimensions(inputInfo, descriptorName, 4, "input");
3710  ValidateTensorNumDimensions(outputInfo, descriptorName, 4, "output");
3711 
3712  std::vector<DataType> supportedTypes =
3713  {
3721  };
3722 
3723  ValidateDataTypes(inputInfo, supportedTypes, descriptorName);
3724  ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
3725 
3726  ValidateTensorNumElementsMatch(inputInfo, outputInfo, descriptorName, "input", "output");
3727 
3728  if (m_Parameters.m_BlockSize == 0)
3729  {
3730  throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
3731  }
3732 
3733  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
3734  const unsigned int wIndex = dimensionIndices.GetWidthIndex();
3735  const unsigned int hIndex = dimensionIndices.GetHeightIndex();
3736  const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
3737 
3738  const TensorShape& outputShape = outputInfo.GetShape();
3739  if (outputShape[hIndex] % m_Parameters.m_BlockSize != 0 || outputShape[wIndex] % m_Parameters.m_BlockSize != 0)
3740  {
3741  throw InvalidArgumentException(descriptorName + ": Output width and height shape"
3742  "must be divisible by block size.");
3743  }
3744 
3745  const TensorShape& inputShape = inputInfo.GetShape();
3746  if (inputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
3747  {
3748  throw InvalidArgumentException(descriptorName + ": The depth of the input tensor"
3749  "must be divisible by the square of block size." );
3750  }
3751 }
3752 
3753 void ComparisonQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3754 {
3755  const std::string descriptorName{"ComparisonQueueDescriptor"};
3756 
3757  ValidateNumInputs(workloadInfo, descriptorName, 2);
3758  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3759 
3760  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3761  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3762  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3763 
3764  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3765  inputTensorInfo1,
3766  outputTensorInfo,
3767  descriptorName,
3768  "input_0",
3769  "input_1");
3770 
3771  if (outputTensorInfo.GetDataType() != DataType::Boolean)
3772  {
3773  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3774  }
3775 }
3776 
3778 {
3779  const std::string descriptorName{"ElementwiseBinaryQueueDescriptor"};
3780 
3781  ValidateNumInputs(workloadInfo, descriptorName, 2);
3782  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3783 
3784  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3785  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3786  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3787 
3788  std::vector<DataType> supportedTypes =
3789  {
3797  };
3798 
3799  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
3800  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
3801 
3802  ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input", "output");
3803  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input", "output");
3804 }
3805 
3807 {
3808  const std::string descriptorName{"ElementwiseUnaryQueueDescriptor"};
3809 
3810  ValidateNumInputs(workloadInfo, descriptorName, 1);
3811  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3812 
3813  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3814  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3815 
3816  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3817 
3818  std::vector<DataType> supportedTypes =
3819  {
3827  };
3828 
3829  std::vector<DataType> logicalSupportedTypes =
3830  {
3832  };
3833 
3835  {
3836  ValidateDataTypes(inputTensorInfo, logicalSupportedTypes, descriptorName);
3837  }
3838  else
3839  {
3840  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3841  }
3842 
3843 
3844  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3845 }
3846 
3847 void RankQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3848 {
3849  const std::string descriptorName{"RankQueueDescriptor"};
3850 
3851  ValidateNumInputs(workloadInfo, descriptorName, 1);
3852  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3853 
3854  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3855  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3856 
3857  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
3858  ValidateTensorNumElements(outputTensorInfo, descriptorName, 1, "output");
3859 
3860  std::vector<DataType> supportedTypes =
3861  {
3870  };
3871 
3872  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3873  ValidateDataTypes(outputTensorInfo, { DataType::Signed32 }, descriptorName);
3874 }
3875 
3877 {
3878  const std::string descriptorName{"LogicalBinaryQueueDescriptor"};
3879 
3880  ValidateNumInputs(workloadInfo, descriptorName, 2);
3881  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3882 
3883  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3884  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3885  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3886 
3887  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3888  inputTensorInfo1,
3889  outputTensorInfo,
3890  descriptorName,
3891  "input_0",
3892  "input_1");
3893 
3894  if (inputTensorInfo0.GetDataType() != DataType::Boolean)
3895  {
3896  throw InvalidArgumentException(descriptorName + ": Input tensor 0 type must be Boolean.");
3897  }
3898 
3899  if (inputTensorInfo1.GetDataType() != DataType::Boolean)
3900  {
3901  throw InvalidArgumentException(descriptorName + ": Input tensor 1 type must be Boolean.");
3902  }
3903 
3904  if (outputTensorInfo.GetDataType() != DataType::Boolean)
3905  {
3906  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3907  }
3908 }
3909 
3910 void ReduceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3911 {
3912  const std::string descriptorName{"ReduceQueueDescriptor"};
3913 
3914  ValidateNumInputs(workloadInfo, descriptorName, 1);
3915  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3916 
3917  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3918  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3919 
3920  std::vector<DataType> supportedTypes =
3921  {
3929  };
3930 
3931  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3932  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3933 }
3934 
3936 {
3937  // Modified from LstmQueueDescriptor::Validate to support UnidirectionalSequenceLstm
3938 
3939  const std::string descriptorName{"UnidirectionalSequenceLstmQueueDescriptor"};
3940 
3941  // check dimensions of all inputs and outputs
3942  if (workloadInfo.m_InputTensorInfos.size() != 3)
3943  {
3944  throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
3945  }
3946  if (workloadInfo.m_OutputTensorInfos.size() != 3)
3947  {
3948  throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
3949  }
3950 
3951  std::vector<DataType> supportedTypes =
3952  {
3955  };
3956 
3957  // check for supported type of one input and match them with all the other input and output
3958  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
3959 
3960  // Making sure clipping parameters have valid values.
3961  // == 0 means no clipping
3962  // > 0 means clipping
3963  if (m_Parameters.m_ClippingThresCell < 0.0f)
3964  {
3965  throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
3966  }
3967  if (m_Parameters.m_ClippingThresProj < 0.0f)
3968  {
3969  throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
3970  }
3971 
3972  unsigned int batchIndx = 0;
3973  unsigned int inputIndx = 1;
3974  uint32_t timeStep = 1;
3975  unsigned int timeIndx = 1;
3976  inputIndx = 2;
3978  {
3979  batchIndx = 1;
3980  timeIndx = 0;
3981 
3982  }
3983  timeStep = workloadInfo.m_InputTensorInfos[0].GetShape()[timeIndx];
3984 
3985  // Inferring batch size, number of outputs and number of cells from the inputs.
3986  const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[inputIndx];
3987  const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[batchIndx];
3988  ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
3989  const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
3990  ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
3991  const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
3992 
3993  // input tensor
3994  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 3, (timeStep * n_batch * n_input),
3995  descriptorName + " input_0");
3996  // outputStateInTensor
3997  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
3998  descriptorName + " input_1");
3999  // outputStateInTensor
4000  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
4001  descriptorName + " input_2");
4002 
4003  // outputTensor
4004  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 3, (timeStep * n_batch * n_output),
4005  descriptorName + " output_0");
4006 
4007  // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
4008  if ( m_InputToInputWeights )
4009  {
4011  (n_cell * n_input), "InputLayerNormWeights");
4012  }
4013 
4014  ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
4016  (n_cell * n_input), "InputToForgetWeights");
4017 
4018  ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
4020  (n_cell * n_input), "InputToCellWeights");
4021 
4023  {
4025  (n_cell * n_output), "RecurrentToInputWeights");
4026  }
4027 
4028  ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
4030  (n_cell * n_output), "RecurrentToForgetWeights");
4031 
4032  ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
4034  (n_cell * n_output), "RecurrentToCellWeights");
4035 
4036  // Make sure the input-gate's parameters are either both present (regular
4037  // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
4038  bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
4042  if (!cifg_weights_all_or_none)
4043  {
4044  throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
4045  "RecurrentToInputWeights must either both be present (regular LSTM) "
4046  "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
4047  "accordingly.");
4048  }
4049 
4050  if ( m_CellToInputWeights )
4051  {
4053  n_cell, "CellToInputWeights");
4054  }
4055  if ( m_CellToForgetWeights )
4056  {
4058  n_cell, "CellToForgetWeights");
4059  }
4060  if ( m_CellToOutputWeights )
4061  {
4063  n_cell, "CellToOutputWeights");
4064  }
4065 
4066  // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
4067  bool peephole_weights_all_or_none =
4072  if (!peephole_weights_all_or_none)
4073  {
4074  throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
4075  }
4076 
4077  // Make sure the input gate bias is present only when not a CIFG-LSTM.
4079  {
4080  if (m_InputGateBias)
4081  {
4082  throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
4083  }
4084  }
4085  else
4086  {
4087  if (!m_InputGateBias)
4088  {
4089  throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
4090  "must be present.");
4091  }
4093  n_cell, "InputGateBias");
4094  }
4095 
4096  ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
4097  ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
4098 
4099  ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
4100  ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
4101 
4102  ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
4103  ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
4104 
4105  if (m_ProjectionWeights)
4106  {
4108  (n_cell * n_output), "ProjectionWeights");
4109  }
4110  if (m_ProjectionBias)
4111  {
4112  ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
4113  }
4114 
4115  // Making sure the projection tensors are consistent:
4116  // 1) If projection weight is not present, then projection bias should not be
4117  // present.
4118  // 2) If projection weight is present, then projection bias is optional.
4119  bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
4125  if (!projecton_tensors_consistent)
4126  {
4127  throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
4128  }
4129 
4130  // The four layer normalization weights either all have values or none of them have values. Additionally, if
4131  // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
4132  // either all have values or none of them have values. Layer normalization is used when the values of all the
4133  // layer normalization weights are present
4135  {
4136  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
4137  }
4139  {
4140  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
4141  }
4143  {
4144  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
4145  }
4147  {
4148  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
4149  }
4150 
4152  {
4154  {
4156  {
4157  throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
4158  "disabled but InputLayerNormWeights are not present");
4159  }
4161  1, n_cell, "InputLayerNormWeights");
4162  }
4163  else if (m_InputLayerNormWeights)
4164  {
4165  throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
4166  "enabled");
4167  }
4168 
4169  ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
4170  "ForgetLayerNormWeights");
4171  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
4172 
4173  ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
4174  "OutputLayerNormWeights");
4175  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
4176 
4177  ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
4178  "CellLayerNormWeights");
4179  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
4180  }
4182  {
4183  throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
4184  "normalisation weights are present.");
4185  }
4186 }
4187 
4189 {
4190  const std::string descriptorName{"BatchMatMulDescriptor"};
4191 
4192  ValidateNumInputs(workloadInfo, descriptorName, 2);
4193  ValidateNumOutputs(workloadInfo, descriptorName, 1);
4194 
4195  // Inputs must be: both 2D+
4196  // For inputs X and Y whose dimensions to be multiplied are (M,N) and (I,J) respectively,
4197  // axes N and I must be the same size
4198 
4199  const auto& inputXInfoBeforeParams = workloadInfo.m_InputTensorInfos[0];
4200  const auto& inputYInfoBeforeParams = workloadInfo.m_InputTensorInfos[1];
4201  const auto& outputInfo = workloadInfo.m_OutputTensorInfos[0];
4202  // Output info has already been inferred
4203 
4204  std::vector<DataType> supportedTypes =
4205  {
4212  };
4213 
4214  ValidateDataTypes(inputXInfoBeforeParams, supportedTypes, descriptorName);
4215  ValidateDataTypes(inputYInfoBeforeParams, supportedTypes, descriptorName);
4216  ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
4217 
4218  if ((inputXInfoBeforeParams.GetNumDimensions() < 2) ||
4219  (inputYInfoBeforeParams.GetNumDimensions() < 2))
4220  {
4221  throw InvalidArgumentException(descriptorName + ": Input tensors are not 2D or greater.");
4222  }
4223 
4224  TensorInfo inputXInfoAfterParams;
4225  TensorInfo inputYInfoAfterParams;
4226 
4229  {
4230  throw InvalidArgumentException(descriptorName +
4231  ": Invalid descriptor parameters - Transpose and Adjoint "
4232  "cannot both be true for a given input tensor.");
4233  }
4235  {
4236  inputXInfoAfterParams = armnnUtils::Permuted(inputXInfoBeforeParams,
4239  inputXInfoBeforeParams.GetShape()));
4240  }
4241  else if(m_Parameters.m_AdjointX)
4242  {
4244  inputXInfoBeforeParams.GetShape());
4245  if(inputXInfoBeforeParams.GetShape()[axesToMul.first] !=
4246  inputXInfoBeforeParams.GetShape()[axesToMul.second])
4247  {
4248  throw InvalidArgumentException(descriptorName +
4249  ": Adjoint is set to true for input tensor X, but the axes to be adjointed are not square." );
4250  }
4251  // Shape remains the same as it's square
4252  inputXInfoAfterParams = inputXInfoBeforeParams;
4253  }
4254  else
4255  {
4256  inputXInfoAfterParams = inputXInfoBeforeParams;
4257  }
4258 
4260  {
4261  inputYInfoAfterParams = armnnUtils::Permuted(inputYInfoBeforeParams,
4264  inputYInfoBeforeParams.GetShape()));
4265  }
4266  else if(m_Parameters.m_AdjointY)
4267  {
4269  inputYInfoBeforeParams.GetShape());
4270  if(inputYInfoBeforeParams.GetShape()[axesToMul.first] !=
4271  inputYInfoBeforeParams.GetShape()[axesToMul.second])
4272  {
4273  throw InvalidArgumentException(descriptorName +
4274  ": Adjoint is set to true for input tensor Y, but the axes to be adjointed are not square." );
4275  }
4276  // Shape remains the same as it's square
4277  inputYInfoAfterParams = inputYInfoBeforeParams;
4278  }
4279  else
4280  {
4281  inputYInfoAfterParams = inputYInfoBeforeParams;
4282  }
4283 
4284  switch(m_Parameters.m_DataLayoutX)
4285  {
4286  case DataLayout::NCDHW:
4287  case DataLayout::NDHWC:
4288  if(inputXInfoAfterParams.GetNumDimensions() < 3)
4289  {
4290  throw InvalidArgumentException(descriptorName +
4291  ": Input tensor X does not have the correct "
4292  "number of dimensions for the Data Layout that it has been assigned.");
4293  }
4294  break;
4295  case DataLayout::NCHW:
4296  case DataLayout::NHWC:
4297  default:
4298  break;
4299  }
4300 
4301  switch(m_Parameters.m_DataLayoutY)
4302  {
4303  case DataLayout::NCDHW:
4304  case DataLayout::NDHWC:
4305  if(inputYInfoAfterParams.GetNumDimensions() < 3)
4306  {
4307  throw InvalidArgumentException(descriptorName +
4308  ": Input tensor Y does not have the correct "
4309  "number of dimensions for the Data Layout that it has been assigned.");
4310  }
4311  break;
4312  case DataLayout::NCHW:
4313  case DataLayout::NHWC:
4314  default:
4315  break;
4316  }
4317 
4319  inputXInfoAfterParams.GetShape());
4321  inputYInfoBeforeParams.GetShape());
4322 
4323  if(inputXInfoAfterParams.GetShape()[axesXToMul.second]
4324  != inputYInfoAfterParams.GetShape()[axesYToMul.first])
4325  {
4326  throw InvalidArgumentException(descriptorName +
4327  ": The final axis of input tensor X must be the same size as "
4328  "the second last axis of input tensor Y.");
4329  }
4330 
4331  { // Separate scope so we don't pollute the rest of the scope with our temp variables
4332  // e.g. NHWC isnt compatible with NCHW as of now
4335 
4336  if(xLayout == DataLayout::NCHW || xLayout == DataLayout::NCDHW)
4337  {
4338  if(yLayout == DataLayout::NHWC || yLayout == DataLayout::NDHWC)
4339  {
4340  throw InvalidArgumentException(descriptorName +
4341  ": Invalid input tensor data layout combination.");
4342  }
4343  }
4344  if(yLayout == DataLayout::NCHW || yLayout == DataLayout::NCDHW)
4345  {
4346  if(xLayout == DataLayout::NHWC || xLayout == DataLayout::NDHWC)
4347  {
4348  throw InvalidArgumentException(descriptorName +
4349  ": Invalid input tensor data layout combination.");
4350  }
4351  }
4352  }
4353 
4354  // Simulate aligning the ends of the matrix dims and prepending 1's to the beginning of the shorter one
4355  unsigned int outputTensorDimSize = std::max(inputXInfoAfterParams.GetNumDimensions(),
4356  inputYInfoAfterParams.GetNumDimensions());
4357  if(outputTensorDimSize-2 > 0)
4358  {
4359  TensorInfo tiXNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4361  TensorInfo tiYNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4363  TensorInfo tiOutNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4365 
4366  auto doAxisExtension = [&](std::vector<unsigned int> axisIndices, TensorInfo& ti)
4367  {
4368  auto sizeDiff = (outputTensorDimSize-2) - axisIndices.size();
4369 
4370  for(unsigned int i = 0; i < sizeDiff; i++)
4371  {
4372  axisIndices.insert(axisIndices.begin(), 1);
4373  }
4374 
4375  for(unsigned int i = 0; i < ti.GetNumDimensions(); i++)
4376  {
4377  ti.GetShape()[i] = inputXInfoAfterParams.GetShape()[i];
4378  }
4379  };
4380 
4382  inputXInfoAfterParams.GetShape());
4384  inputYInfoAfterParams.GetShape());
4385 
4386  doAxisExtension(axesXNotMul, tiXNotMul);
4387  doAxisExtension(axesYNotMul, tiYNotMul);
4388 
4389  for(unsigned int i = 0; i < tiOutNotMul.GetNumDimensions(); i++)
4390  {
4391  tiOutNotMul.GetShape()[i] = std::max(tiXNotMul.GetShape()[i],
4392  tiYNotMul.GetShape()[i]);
4393  }
4394 
4395  ValidateBroadcastTensorShapesMatch(tiXNotMul,
4396  tiYNotMul,
4397  tiOutNotMul,
4398  descriptorName,
4399  "input_X",
4400  "input_Y");
4401  }
4402 }
4403 
4404 void TileQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
4405 {
4406  const std::string& descriptorName{"TileQueueDescriptor"};
4407 
4408  ValidateNumInputs(workloadInfo, descriptorName, 1);
4409  ValidateNumOutputs(workloadInfo, descriptorName, 1);
4410 
4411  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
4412  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
4413 
4414  std::vector<DataType> supportedTypes =
4415  {
4424  };
4425 
4426  // Multiples length must be the same as the number of dimensions in input.
4427  if (m_Parameters.m_Multiples.size() != inputTensorInfo.GetNumDimensions())
4428  {
4429  throw InvalidArgumentException(descriptorName +
4430  ": Multiples length is not same as the number of dimensions in Input.");
4431  }
4432 
4433  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
4434  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
4435 }
4436 
4438 {
4439  const std::string& descriptorName{"BroadcastToQueueDescriptor"};
4440 
4441  ValidateNumInputs(workloadInfo, descriptorName, 1);
4442  ValidateNumOutputs(workloadInfo, descriptorName, 1);
4443 
4444  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
4445  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
4446 
4447  std::vector<DataType> supportedTypes =
4448  {
4457  };
4458 
4459  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
4460  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
4461 }
4462 
4463 void ScatterNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
4464 {
4465  const std::string& descriptorName{"ScatterQueueDescriptor"};
4466 
4467  ValidateNumInputs(workloadInfo, descriptorName, 3);
4468  ValidateNumOutputs(workloadInfo, descriptorName, 1);
4469 
4470  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
4471  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
4472  const TensorInfo& inputTensorInfo2 = workloadInfo.m_InputTensorInfos[2];
4473  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
4474 
4475  std::vector<DataType> supportedTypes =
4476  {
4484  };
4485 
4486  std::vector<DataType> indicesSupportedTypes =
4487  {
4489  };
4490 
4492  {
4493  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
4494  }
4495  else
4496  {
4497  ValidateDataTypes(inputTensorInfo0, indicesSupportedTypes, descriptorName);
4498  }
4499 
4500  ValidateDataTypes(inputTensorInfo1, indicesSupportedTypes, descriptorName);
4501  ValidateDataTypes(inputTensorInfo2, supportedTypes, descriptorName);
4502  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
4503 }
4504 
4505 } // namespace armnn
#define CHECK_LOCATION()
Definition: Exceptions.hpp:203
const TensorInfo & GetTensorInfo() const
TensorShape GetShape() const override
Get the number of elements for each dimension ordered from slowest iterating dimension to fastest ite...
bool has_value() const noexcept
Definition: Optional.hpp:53
SizeType GetSize() const
Definition: Types.hpp:359
float GetQuantizationScale() const
Definition: Tensor.cpp:461
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:197
bool IsTypeSpaceMatch(const TensorInfo &other) const
Check that the types are the same and, if quantize, that the quantization parameters are the same.
Definition: Tensor.cpp:432
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:482
bool IsQuantized() const
Definition: Tensor.cpp:508
unsigned int GetNumElements() const
Definition: Tensor.hpp:198
const TensorShape & GetShape() const
Definition: Tensor.hpp:193
Optional< unsigned int > GetQuantizationDim() const
Definition: Tensor.cpp:498
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:451
bool HasPerAxisQuantization() const
Definition: Tensor.cpp:446
DataType GetDataType() const
Definition: Tensor.hpp:200
bool HasMultipleQuantizationScales() const
Definition: Tensor.hpp:203
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
Provides access to the appropriate indexes for Channels, Height and Width based on DataLayout.
unsigned int GetWidthIndex() const
unsigned int GetHeightIndex() const
unsigned int GetChannelsIndex() const
Copyright (c) 2021 ARM Limited and Contributors.
constexpr const char * GetDataTypeName(DataType dataType)
Definition: TypesUtils.hpp:234
DataType GetBiasDataType(DataType inputDataType)
DataLayout
Definition: Types.hpp:63
constexpr bool IsQuantizedType()
Definition: TypesUtils.hpp:312
DataType
Definition: Types.hpp:49
constexpr bool IsQuantized8BitType(DataType dataType)
Definition: TypesUtils.hpp:317
armnn::TensorShape Permuted(const armnn::TensorShape &srcShape, const armnn::PermutationVector &mappings)
Definition: Permute.cpp:125
unsigned int GetUnsignedAxis(const unsigned int inputDimension, const int axis)
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
int m_Axis
Axis to reduce across the input tensor.
Definition: Descriptors.hpp:83
void Validate(const WorkloadInfo &workloadInfo) const
bool m_AdjointX
Adjoint the slices of each input tensor Transpose and Adjoint can not both be set to true for the sam...
static std::pair< unsigned int, unsigned int > GetAxesToMul(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the two axes (for each input) for multiplication.
static PermutationVector GetPermuteVec(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the axes which will be transposed.
static std::vector< unsigned int > GetAxesNotMul(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the axes (for each input) that will not be multiplied together.
bool m_TransposeX
Transpose the slices of each input tensor Transpose and Adjoint can not both be set to true for the s...
DataLayout m_DataLayoutX
Data layout of each input tensor, such as NHWC/NDHWC (leave as default for arbitrary layout)
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_Variance
std::vector< unsigned int > m_BlockShape
Block shape values.
std::vector< std::pair< unsigned int, unsigned int > > m_Crops
The values to crop from the input dimension.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< unsigned int > m_Origin
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< ViewOrigin > m_ViewOrigins
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_LayerOutput
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
bool m_BiasEnabled
Enable/disable bias.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
void Validate(const WorkloadInfo &workloadInfo) const
uint32_t m_StrideZ
Stride value when proceeding through input for the depth dimension.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
bool m_BiasEnabled
Enable/disable bias.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
uint32_t m_DilationY
Dilation factor value for height dimension.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
uint32_t m_DilationX
Dilation factor value for width dimension.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
bool m_BiasEnabled
Enable/disable bias.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
uint32_t m_NumClasses
Number of classes.
float m_NmsIouThreshold
Intersection over union threshold.
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_Anchors
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
UnaryOperation m_Operation
Specifies the elementwiseUnary operation to execute.
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
bool m_BiasEnabled
Enable/disable bias.
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
bool m_PeepholeEnabled
Enable/disable peephole.
bool m_TimeMajor
Enable/disable time major.
bool m_LayerNormEnabled
Enable/disable layer normalization.
float m_ClippingThresCell
Clipping threshold value for the cell state.
bool m_ProjectionEnabled
Enable/disable the projection layer.
float m_ClippingThresProj
Clipping threshold value for the projection.
bool m_CifgEnabled
Enable/disable cifg (coupled input & forget gate).
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_OutputLayerNormWeights
const ConstTensorHandle * m_InputToOutputWeights
const ConstTensorHandle * m_InputLayerNormWeights
const ConstTensorHandle * m_CellToForgetWeights
const ConstTensorHandle * m_RecurrentToInputWeights
const ConstTensorHandle * m_ForgetGateBias
const ConstTensorHandle * m_ProjectionWeights
const ConstTensorHandle * m_InputGateBias
const ConstTensorHandle * m_RecurrentToOutputWeights
const ConstTensorHandle * m_OutputGateBias
const ConstTensorHandle * m_CellBias
const ConstTensorHandle * m_InputToCellWeights
const ConstTensorHandle * m_CellToInputWeights
const ConstTensorHandle * m_CellToOutputWeights
const ConstTensorHandle * m_InputToForgetWeights
const ConstTensorHandle * m_InputToInputWeights
const ConstTensorHandle * m_RecurrentToCellWeights
const ConstTensorHandle * m_ProjectionBias
const ConstTensorHandle * m_ForgetLayerNormWeights
const ConstTensorHandle * m_RecurrentToForgetWeights
const ConstTensorHandle * m_CellLayerNormWeights
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< unsigned int > m_Axis
Values for the dimensions to reduce.
bool m_KeepDims
Enable/disable keep dimensions. If true, then the reduced dimensions that are of length 1 are kept.
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
unsigned int GetConcatAxis() const
Get the concatenation axis value.
std::vector< std::pair< unsigned int, unsigned int > > m_PadList
Specifies the padding for input dimension.
void Validate(const WorkloadInfo &workloadInfo) const
PermutationVector m_DimMappings
Indicates how to translate tensor elements from a given source into the target destination,...
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
bool m_PeepholeEnabled
Enable/disable peephole.
int32_t m_HiddenStateZeroPoint
Hidden State zero point.
bool m_LayerNormEnabled
Enable/disable layer normalization.
bool m_ProjectionEnabled
Enable/disable the projection layer.
bool m_CifgEnabled
Enable/disable CIFG (coupled input & forget gate).
float m_HiddenStateScale
Hidden State quantization scale.
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_OutputLayerNormWeights
const ConstTensorHandle * m_InputToOutputWeights
const ConstTensorHandle * m_InputLayerNormWeights
const ConstTensorHandle * m_CellToForgetWeights
const ConstTensorHandle * m_RecurrentToInputWeights
const ConstTensorHandle * m_ForgetGateBias
const ConstTensorHandle * m_ProjectionWeights
const ConstTensorHandle * m_InputGateBias
const ConstTensorHandle * m_RecurrentToOutputWeights
const ConstTensorHandle * m_OutputGateBias
const ConstTensorHandle * m_CellBias
const ConstTensorHandle * m_InputToCellWeights
const ConstTensorHandle * m_CellToInputWeights
const ConstTensorHandle * m_CellToOutputWeights
const ConstTensorHandle * m_InputToForgetWeights
const ConstTensorHandle * m_InputToInputWeights
const ConstTensorHandle * m_RecurrentToCellWeights
const ConstTensorHandle * m_ProjectionBias
const ConstTensorHandle * m_ForgetLayerNormWeights
const ConstTensorHandle * m_RecurrentToForgetWeights
const ConstTensorHandle * m_CellLayerNormWeights
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_InputToOutputWeights
const ConstTensorHandle * m_RecurrentToInputWeights
const ConstTensorHandle * m_ForgetGateBias
const ConstTensorHandle * m_InputGateBias
const ConstTensorHandle * m_RecurrentToOutputWeights
const ConstTensorHandle * m_OutputGateBias
const ConstTensorHandle * m_CellBias
const ConstTensorHandle * m_InputToCellWeights
const ConstTensorHandle * m_InputToForgetWeights
const ConstTensorHandle * m_InputToInputWeights
const ConstTensorHandle * m_RecurrentToCellWeights
const ConstTensorHandle * m_RecurrentToForgetWeights
void ValidateTensorNumDimensions(const TensorInfo &tensor, std::string const &descName, unsigned int numDimensions, std::string const &tensorName) const
std::vector< ITensorHandle * > m_Inputs
std::vector< ITensorHandle * > m_Outputs
void ValidateInputsOutputs(const std::string &descName, unsigned int numExpectedIn, unsigned int numExpectedOut) const
void ValidateTensorNumDimNumElem(const TensorInfo &tensorInfo, unsigned int numDimension, unsigned int numElements, std::string const &tensorName) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
bool m_InputEnabled
Flag to show if input tensor is accepted.
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< unsigned int > m_Begin
Beginning indices of the slice in each dimension.
std::vector< unsigned int > m_Size
Size of the slice in each dimension.
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< unsigned int > m_BlockShape
Block shape value.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
std::vector< std::pair< unsigned int, unsigned int > > m_PadList
Specifies the padding values for the input dimension: heightPad{top, bottom} widthPad{left,...
void Validate(const WorkloadInfo &workloadInfo) const
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
unsigned int m_BlockSize
Scalar specifying the input block size. It must be >= 1.
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< unsigned int > m_Origin
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< ViewOrigin > m_ViewOrigins
TensorShape m_InputShape
Required shape of all input tensors.
uint32_t m_Axis
0-based axis along which to stack the input tensors.
uint32_t m_NumInputs
Number of input tensors.
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< int > m_Stride
Stride values for the input that will be sliced.
std::vector< int > m_Begin
Begin values for the input that will be sliced.
std::vector< int > m_End
End values for the input that will be sliced.
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< uint32_t > m_Multiples
The vector to multiply the input shape by.
void Validate(const WorkloadInfo &workloadInfo) const
bool m_BiasEnabled
Enable/disable bias.
void Validate(const WorkloadInfo &workloadInfo) const
PermutationVector m_DimMappings
Indicates how to translate tensor elements from a given source into the target destination,...
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_RecurrentToOutputWeights
const ConstTensorHandle * m_RecurrentToForgetWeights
void Validate(const WorkloadInfo &workloadInfo) const
Contains information about TensorInfos of a layer.
std::vector< TensorInfo > m_OutputTensorInfos
std::vector< TensorInfo > m_InputTensorInfos