ArmNN
 22.11
WorkloadData.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2022 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  return DataType::Signed32;
39  case DataType::QAsymmU8:
40  return DataType::Signed32;
41  case DataType::QSymmS8:
42  return DataType::Signed32;
43  case DataType::QSymmS16:
44  return DataType::Signed32;
45  default:
46  ARMNN_ASSERT_MSG(false, "Invalid input data type");
47  return DataType::Float32;
48  }
49 }
50 
51 namespace
52 {
53 
54 //---------------------------------------------------------------
55 //android ndk does not support std::to_string function.
56 template <typename T>
57 std::string to_string(T value)
58 {
59  std::ostringstream os;
60  os << value;
61  return os.str();
62 }
63 
64 //---------------------------------------------------------------
65 void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName)
66 {
67  if (!ptr)
68  {
69  throw InvalidArgumentException(descName + ": Invalid null pointer. The " +
70  paramName + " parameter must be set.");
71  }
72 }
73 
74 //---------------------------------------------------------------
75 void ValidateTensorShapesMatch(const TensorInfo& first,
76  const TensorInfo& second,
77  std::string const& descName,
78  std::string const& firstName,
79  std::string const& secondName)
80 {
81  if (first.GetShape() != second.GetShape())
82  {
83  throw InvalidArgumentException(descName + ": "
84  + firstName + " & " + secondName + " must have identical shapes");
85  }
86 }
87 
88 //---------------------------------------------------------------
89 void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
90 {
91  if (workloadInfo.m_InputTensorInfos.size() != expectedSize)
92  {
93  throw InvalidArgumentException(descName +
94  ": Requires exactly " + to_string(expectedSize) + "input(s). " +
95  to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided.");
96  }
97 }
98 
99 //---------------------------------------------------------------
100 void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
101 {
102  if (workloadInfo.m_OutputTensorInfos.size() != expectedSize)
103  {
104  throw InvalidArgumentException(descName +
105  ": Requires exactly " + to_string(expectedSize) + " output(s). " +
106  to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
107  }
108 }
109 
110 //---------------------------------------------------------------
111 
112 //---------------------------------------------------------------
113 void ValidateTensorNumElements(const TensorInfo& tensor,
114  std::string const& descName,
115  unsigned int numElements,
116  std::string const& tensorName)
117 {
118  if (tensor.GetNumElements() != numElements)
119  {
120  throw InvalidArgumentException(descName + ": Expected " + to_string(numElements) + " but got " +
121  to_string(tensor.GetNumElements()) + " elements for " +
122  tensorName + " tensor.");
123  }
124 }
125 
126 //---------------------------------------------------------------
127 void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
128  const std::string& descName, std::string const& tensorName)
129 {
130  if (tensor.GetDataType() != dataType)
131  {
132  throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
133  GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
134  }
135 }
136 
137 void ValidPerAxisQuantizedDataType(const TensorInfo& tensor, const std::string& descName, const std::string& tensorName)
138 {
139  if (tensor.GetDataType() != DataType::QSymmS8)
140  {
141  throw InvalidArgumentException(descName +
142  ": Expected data type which supports per-axis quantization scheme but got " +
143  GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
144  }
145 }
146 
147 //---------------------------------------------------------------
148 void ValidateTensorQuantizationSpace(const TensorInfo& first,
149  const TensorInfo& second,
150  const std::string& descName,
151  std::string const& firstName,
152  std::string const& secondName)
153 {
154  if (!first.IsQuantized() ||
155  !second.IsQuantized())
156  {
157  // Not a quantized type, ignore the validation
158  return;
159  }
160 
161  DataType firstDataType = first.GetDataType();
162  DataType secondDataType = second.GetDataType();
163 
164  if (firstDataType != secondDataType)
165  {
166  throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
167  " must be of the same quantized type, " +
168  firstName + " is " + GetDataTypeName(firstDataType) + ", " +
169  secondName + " is " + GetDataTypeName(secondDataType));
170  }
171 
172  if (!first.IsTypeSpaceMatch(second))
173  {
174  throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
175  " must have the same quantization space, " +
176  firstName + " has offset " + to_string(first.GetQuantizationOffset()) +
177  " and scale " + to_string(first.GetQuantizationScale()) + ", " +
178  secondName + " has offset " + to_string(second.GetQuantizationOffset()) +
179  " and scale " + to_string(second.GetQuantizationScale()));
180  }
181 }
182 
183 //---------------------------------------------------------------
184 void ValidateBiasTensorQuantization(const TensorInfo& biasTensor,
185  const TensorInfo& inputTensorInfo,
186  const TensorInfo& weightsTensorInfo,
187  const std::string& descName)
188 {
189  // Helper lambda function to validate a single bias quantization scale value
190  auto VerifyBiasQuantizationScale = [&descName](float biasScale, float expectedScale) -> void
191  {
192  constexpr float tolerance = 0.0001f;
193  if (std::abs(biasScale - expectedScale) > tolerance)
194  {
195  // Print the float values with extra precision to see very small differences
196  ARMNN_LOG(warning) << std::setprecision(6) << descName << ": Expected " << expectedScale <<
197  " for bias quantization scale (product of input and weight scales), but got " <<
198  biasScale << ". Using scale provided.";
199  }
200  };
201 
202  if (biasTensor.GetQuantizationOffset() != 0)
203  {
204  throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
205  to_string(biasTensor.GetQuantizationOffset()));
206  }
207 
208  if (biasTensor.HasMultipleQuantizationScales() || weightsTensorInfo.HasMultipleQuantizationScales())
209  {
210  // Validate per-axis quantization scales
211  const std::vector<float>& weightScales = weightsTensorInfo.GetQuantizationScales();
212  const std::vector<float>& biasScales = biasTensor.GetQuantizationScales();
213 
214  if (weightScales.size() != biasScales.size())
215  {
216  std::stringstream msg;
217  msg << descName << ": Expected matching number of per-axis quantization scales for weights and bias, "
218  << "but got different values. This is currently unsupported: weights=" << weightScales.size()
219  << ", biases=" << biasScales.size();
220  throw InvalidArgumentException(msg.str(), CHECK_LOCATION());
221  }
222 
223  for (size_t i = 0ul; i < biasScales.size(); ++i)
224  {
225  const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightScales[i];
226  VerifyBiasQuantizationScale(biasScales[i], expectedScale);
227  }
228  }
229  else
230  {
231  // Validate per-tensor quantization scale
232  const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightsTensorInfo.GetQuantizationScale();
233  VerifyBiasQuantizationScale(biasTensor.GetQuantizationScale(), expectedScale);
234  }
235 }
236 
237 //---------------------------------------------------------------
238 void ValidateTensors(const std::vector<ITensorHandle*>& vec,
239  unsigned int numExpected,
240  const std::string& descName,
241  const std::string& varName)
242 {
243  if (vec.empty() && numExpected > 0)
244  {
245  throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
246  }
247 
248  for (unsigned int i = 0; i < numExpected; ++i)
249  {
250  if (!vec[i])
251  {
252  throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
253  }
254  }
255 }
256 
257 //---------------------------------------------------------------
258 void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
259  const TensorInfo& second,
260  const TensorInfo& output,
261  std::string const& descName,
262  std::string const& firstName,
263  std::string const& secondName)
264 {
265  // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
266  // broadcasted.
267  if (first.GetNumDimensions() != second.GetNumDimensions())
268  {
269  throw InvalidArgumentException(descName + ": Tensors "
270  + firstName + " & " + secondName
271  + " must have the same number of dimensions in order to be broadcasted");
272  }
273  uint32_t numDims = first.GetNumDimensions();
274  std::vector<uint32_t> outputDims(numDims, 0u);
275  for (uint32_t i = 0; i < numDims; i++)
276  {
277  const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i];
278  const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1);
279  if (dimsNotEqual && dimsNotOne)
280  {
281  throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes");
282  }
283  outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]);
284  }
285  TensorShape broadcastShape = TensorShape(armnn::numeric_cast<unsigned int>(outputDims.size()), outputDims.data());
286  if (broadcastShape != output.GetShape())
287  {
288  throw InvalidArgumentException(descName + ": The tensor shape resulting from adding "
289  + firstName + " & " + secondName
290  + " does not match the output shape");
291  }
292 }
293 
294 //---------------------------------------------------------------
295 void ValidateDataTypes(const TensorInfo& info,
296  const std::vector<armnn::DataType>& supportedTypes,
297  std::string const& descName)
298 {
299  auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
300  if (iterator == supportedTypes.end())
301  {
302  throw InvalidArgumentException(descName + ": " + " Tensor type is not supported.");
303  }
304 }
305 
306 //---------------------------------------------------------------
307 void ValidateTensorDataTypesMatch(const TensorInfo& first,
308  const TensorInfo& second,
309  std::string const& descName,
310  std::string const& firstName,
311  std::string const& secondName)
312 {
313  if (first.GetDataType() != second.GetDataType())
314  {
315  throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
316  " must have identical data types.");
317  }
318 }
319 
320 //---------------------------------------------------------------
321 void ValidateTensorNumElementsMatch(const TensorInfo& first,
322  const TensorInfo& second,
323  std::string const& descName,
324  std::string const& firstName,
325  std::string const& secondName)
326 {
327  if (first.GetNumElements() != second.GetNumElements())
328  {
329  throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
330  " must have the same number of elements.");
331  }
332 }
333 
334 void ValidateWeightDataType(const TensorInfo& inputInfo,
335  const TensorInfo& weightInfo,
336  const std::string& descName)
337 {
338  const DataType inputType = inputInfo.GetDataType();
339  if (IsQuantized8BitType(inputType))
340  {
341  const std::vector<DataType> validTypes =
342  {
343  DataType::QAsymmS8,
344  DataType::QAsymmU8,
345  DataType::QSymmS8
346  };
347 
348  ValidateDataTypes(weightInfo, validTypes, descName);
349  }
350  else
351  {
352  ValidateTensorDataTypesMatch(inputInfo, weightInfo, descName, "input", "weight");
353  }
354 }
355 
356 void ValidatePerAxisQuantizationDimension(const TensorInfo& tensorInfo,
357  const std::string& descName,
358  const std::string& tensorName)
359 {
360  const Optional<unsigned int>& quantizationDim = tensorInfo.GetQuantizationDim();
361  if (!quantizationDim.has_value())
362  {
363  throw InvalidArgumentException(fmt::format("{0}: Quantization dimension for per-axis quantization "
364  "not set on tensor {1}.", descName, tensorName));
365  }
366 }
367 
368 void ValidatePerAxisQuantizationOffset(const TensorInfo& tensorInfo,
369  const std::string& descName,
370  const std::string& tensorName)
371 {
372  int32_t quantizationOffset = tensorInfo.GetQuantizationOffset();
373  if (quantizationOffset != 0)
374  {
375  throw InvalidArgumentException(fmt::format(
376  "{0}: Quantization offset for per-axis quantization expected to be 0 on tensor {1}, but got: {2}",
377  descName, tensorName, quantizationOffset));
378  }
379 }
380 
381 void ValidatePerAxisQuantization(const TensorInfo& inputInfo,
382  const TensorInfo& outputInfo,
383  const TensorInfo& weightInfo,
384  const Optional<TensorInfo>& optionalBiasInfo,
385  const std::string& descName)
386 {
387  if (weightInfo.HasPerAxisQuantization())
388  {
389  const DataType inputDataType = inputInfo.GetDataType();
390  const DataType outputDataType = outputInfo.GetDataType();
391 
392  const bool canHavePerAxisQuantization = (IsQuantized8BitType(inputDataType)) && inputDataType == outputDataType;
393 
394  if (!canHavePerAxisQuantization)
395  {
396  throw InvalidArgumentException(fmt::format(
397  "{0}: Per-axis quantization parameters set on tensor {1}, but data type does not support "
398  "per-axis quantization.", descName, "weight"));
399  }
400 
401 
402  ValidPerAxisQuantizedDataType(weightInfo, descName, "weight");
403  ValidatePerAxisQuantizationDimension(weightInfo, descName, "weight");
404  ValidatePerAxisQuantizationOffset(weightInfo, descName, "weight");
405 
406  if (optionalBiasInfo.has_value())
407  {
408  const TensorInfo& biasInfo = optionalBiasInfo.value();
409  if (!biasInfo.HasPerAxisQuantization())
410  {
411  throw InvalidArgumentException(fmt::format(
412  "{}: Per-axis quantization parameters not set on bias tensor, "
413  "despite being set on weight tensor.", descName));
414  }
415 
416  ValidateTensorDataType(biasInfo, DataType::Signed32, descName, "bias");
417  ValidatePerAxisQuantizationDimension(biasInfo, descName, "bias");
418  ValidatePerAxisQuantizationOffset(biasInfo, descName, "bias");
419  }
420  }
421 }
422 
423 } // anonymous namespace
424 
425 //---------------------------------------------------------------
427  std::string const& descName,
428  unsigned int numDimensions,
429  std::string const& tensorName) const
430 {
431  // If we're allowing expanded dimensions then numDimensions becomes the minimum number of Dimensions we can allow.
432  // Throw an Exception if the tensors has fewer than numDimensions or if the squeezed dimensions are greater than
433  // numDimensions.
435  {
436  unsigned int squeezedDims = 0;
437 
438  for (unsigned int i = 0; i < tensor.GetNumDimensions(); ++i)
439  {
440  if (tensor.GetShape()[i] != 1)
441  {
442  ++squeezedDims;
443  }
444  }
445  if (tensor.GetNumDimensions() < numDimensions || squeezedDims > numDimensions)
446  {
447  throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " or less but got " +
448  to_string(tensor.GetNumDimensions()) + " dimensions for " +
449  tensorName + " tensor.");
450  }
451  }
452  else
453  {
454  if (tensor.GetNumDimensions() != numDimensions)
455  {
456  throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " +
457  to_string(tensor.GetNumDimensions()) + " dimensions for " +
458  tensorName + " tensor.");
459  }
460  }
461 }
462 
463 //---------------------------------------------------------------
465  unsigned int numDimension,
466  unsigned int numElements,
467  std::string const& tensorName) const
468 {
469  const std::string functionName{"ValidateTensorNumDimNumElem"};
470  ValidateTensorNumDimensions(tensorInfo, functionName, numDimension, tensorName);
471  ValidateTensorNumElements(tensorInfo, functionName, numElements, tensorName);
472 }
473 
474 //---------------------------------------------------------------
475 void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
476  unsigned int numExpectedIn, unsigned int numExpectedOut) const
477 {
478  ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
479  ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
480 }
481 
482 //---------------------------------------------------------------
483 void MapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
484 {
485  const std::string descriptorName{"MapQueueDescriptor"};
486 
487  ValidateNumInputs(workloadInfo, descriptorName, 1);
488  ValidateNumOutputs(workloadInfo, descriptorName, 0);
489 
490  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
491  {
492  if (!m_Inputs[i])
493  {
495  fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
496  }
497  }
498 }
499 
500 //---------------------------------------------------------------
501 void UnmapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
502 {
503  const std::string descriptorName{"UnmapQueueDescriptor"};
504 
505  ValidateNumInputs(workloadInfo, descriptorName, 1);
506  ValidateNumOutputs(workloadInfo, descriptorName, 0);
507 
508  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
509  {
510  if (!m_Inputs[i])
511  {
513  fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
514  }
515  }
516 }
517 
518 //---------------------------------------------------------------
519 void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
520 {
521  const std::string descriptorName{"MemCopyQueueDescriptor"};
522 
523  ValidateNumInputs(workloadInfo, descriptorName, 1);
524  ValidateNumOutputs(workloadInfo, descriptorName , 1);
525 
526  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
527  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
528 
529  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
530  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
531 
532  if (m_Inputs.size() != m_Outputs.size())
533  {
534  throw InvalidArgumentException(fmt::format(
535  "{0}: Number of inputs ({1}) does not match the number of outputs ({2}).",
536  descriptorName, m_Inputs.size(), m_Outputs.size()));
537  }
538 
539  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
540  {
541  if (!m_Inputs[i])
542  {
543  throw InvalidArgumentException(fmt::format(
544  "{0}: Invalid NULL input {1}.", descriptorName, i));
545  }
546 
547  if (!m_Outputs[i])
548  {
549  throw InvalidArgumentException(fmt::format("{0}: Invalid NULL output {1}", descriptorName, i));
550  }
551  }
552 }
553 
554 //---------------------------------------------------------------
555 void MemImportQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
556 {
557  ValidateNumInputs(workloadInfo, "MemImportQueueDescriptor", 1);
558  ValidateNumOutputs(workloadInfo, "MemImportQueueDescriptor" , 1);
559 
560  if (workloadInfo.m_InputTensorInfos.size() != 1)
561  {
562  throw InvalidArgumentException(fmt::format("Number of input infos ({}) is not 1.",
563  workloadInfo.m_InputTensorInfos.size()));
564 
565  }
566 
567  if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
568  {
569  throw InvalidArgumentException(fmt::format(
570  "Number of input infos ({0}) does not match the number of output infos ({1})",
571  workloadInfo.m_InputTensorInfos.size(), workloadInfo.m_OutputTensorInfos.size()));
572  }
573 
574  for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
575  {
576  if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
577  workloadInfo.m_OutputTensorInfos[i].GetNumElements())
578  {
579  throw InvalidArgumentException(fmt::format(
580  "Number of elements for tensor input and output {} does not match", i ));
581  }
582  }
583 
584  if (m_Inputs.size() != 1)
585  {
586  throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
587  }
588 
589  if (m_Inputs.size() != m_Outputs.size())
590  {
591  throw InvalidArgumentException(fmt::format(
592  "Number of inputs ({0}) does not match the number of outputs ({1})",
593  m_Inputs.size(), m_Outputs.size()));
594  }
595 
596  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
597  {
598  if (!m_Inputs[i])
599  {
600  throw InvalidArgumentException(fmt::format("Invalid null input {}", i));
601  }
602 
603  if (!m_Outputs[i])
604  {
605  throw InvalidArgumentException(fmt::format("Invalid null output {}", i));
606  }
607  }
608 }
609 
610 //---------------------------------------------------------------
611 void MemSyncQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
612 {
613  ValidateNumInputs(workloadInfo, "MemSyncQueueDescriptor", 1);
614 
615  if (m_Inputs.size() != 1)
616  {
617  throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
618  }
619 
620  if (m_Outputs.size() != 0)
621  {
622  throw InvalidArgumentException(fmt::format("Number of outputs ({}) is not 0.", m_Outputs.size()));
623  }
624 
625  if (!m_Inputs[0])
626  {
627  throw InvalidArgumentException(fmt::format("Invalid null input 0"));
628  }
629 }
630 
631 //---------------------------------------------------------------
632 void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
633 {
634  const std::string descriptorName{"ActivationQueueDescriptor"};
635 
636  ValidateNumInputs(workloadInfo, descriptorName, 1);
637  ValidateNumOutputs(workloadInfo, descriptorName, 1);
638 
639  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
640  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
641 
642  std::vector<DataType> supportedTypes =
643  {
650  };
651 
652  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
653  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
654  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
655 }
656 
657 void ArgMinMaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
658 {
659  const std::string descriptorName{"ArgMinMaxQueueDescriptor"};
660 
661  ValidateNumInputs(workloadInfo, descriptorName, 1);
662  ValidateNumOutputs(workloadInfo, descriptorName, 1);
663 
664  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
665  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
666 
667  if (outputTensorInfo.GetDataType() != DataType::Signed32 &&
668  outputTensorInfo.GetDataType() != DataType::Signed64)
669  {
670  throw InvalidArgumentException(descriptorName + ": Output of ArgMinMax layer must be Int32 or Int64.");
671  }
672 
673  std::vector<DataType> supportedInputTypes =
674  {
683  };
684 
685  ValidateDataTypes(inputTensorInfo, supportedInputTypes, descriptorName);
686 
687  auto inputShape = inputTensorInfo.GetShape();
688  auto outputShape = outputTensorInfo.GetShape();
689 
690  auto inputNumDimensions = inputShape.GetNumDimensions();
691  auto unsignedAxis = armnnUtils::GetUnsignedAxis(inputNumDimensions, m_Parameters.m_Axis);
692 
693  const std::string outputShapeError{": Output tensor shape does not match shape inferred from input tensor."};
694 
695  // 1D input shape results in scalar output shape
696  if (inputShape.GetNumDimensions() == 1)
697  {
698  if (outputShape.GetNumDimensions() != 1 && outputShape[0] != 1)
699  {
700  throw InvalidArgumentException(descriptorName + outputShapeError);
701  }
702  }
703  else
704  {
705  for (unsigned int i = 0; i < unsignedAxis; ++i)
706  {
707  if (outputShape[i] != inputShape[i])
708  {
709  throw InvalidArgumentException(descriptorName + outputShapeError);
710  }
711  }
712 
713  for (auto i = unsignedAxis + 1; i < inputNumDimensions; ++i)
714  {
715  if (outputShape[i - 1] != inputShape[i])
716  {
717  throw InvalidArgumentException(descriptorName + outputShapeError);
718  }
719  }
720  }
721 }
722 
723 void CastQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
724 {
725  const std::string descriptorName{"CastQueueDescriptor"};
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  {
744  };
745 
746  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
747  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
748 }
749 
750 void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
751 {
752  const std::string descriptorName{"SoftmaxQueueDescriptor"};
753 
754  ValidateNumInputs(workloadInfo, descriptorName, 1);
755  ValidateNumOutputs(workloadInfo, descriptorName, 1);
756 
757  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
758  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
759 
760  std::vector<DataType> supportedTypes =
761  {
768  };
769 
770  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
771  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
772  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
773 }
774 
775 void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
776 {
777  const std::string descriptorName{"SplitterQueueDescriptor"};
778 
779  ValidateNumInputs(workloadInfo, descriptorName, 1);
780 
781  // Check the supported data types
782  std::vector<DataType> supportedTypes =
783  {
792  };
793 
794  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
795  for (unsigned long i = 0ul; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
796  {
797  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[i];
798  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
799 
800  const std::string outputName = "output_" + std::to_string(i);
801  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", outputName);
802  }
803 
804  if (workloadInfo.m_OutputTensorInfos.size() <= 0)
805  {
806  throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
807  }
808 
809  if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
810  {
812  descriptorName + ": Number of split windows "
813  "has to match number of workloadInfo.m_OutputTensorInfos. "
814  "Number of windows: " +
815  to_string(m_ViewOrigins.size()) +
816  ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
817  }
818 
819  //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
820  std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
821  for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
822  {
823  //Checks that the dimensionality of input is same as the split windows.
824  ViewOrigin const& e = m_ViewOrigins[w];
825  if (e.m_Origin.size() != inputDims)
826  {
827  throw InvalidArgumentException(descriptorName + ": Window origin have to "
828  "have the same dimensionality as the input tensor. "
829  "Window origin (index: " +
830  to_string(w) + ") has " + to_string(e.m_Origin.size()) +
831  " dimensions, the input "
832  "tensor has " +
833  to_string(inputDims) + " dimensions.");
834  }
835  for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
836  {
837  if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
838  workloadInfo.m_InputTensorInfos[0].GetShape()[i])
839  {
840  throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
841  "be smaller or equal than the size of the input in that coord.");
842  }
843  }
844  }
845 }
846 
847 void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
848 {
849  const std::string descriptorName{"ConcatQueueDescriptor"};
850 
851  ValidateNumOutputs(workloadInfo, descriptorName, 1);
852 
853  if (m_Inputs.size() <= 0)
854  {
855  throw InvalidArgumentException(descriptorName + ": At least one input needs to be provided.");
856  }
857  if (m_Outputs.size() <= 0)
858  {
859  throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
860  }
861 
862  if (workloadInfo.m_InputTensorInfos.size() <= 0)
863  {
864  throw InvalidArgumentException(descriptorName + ": At least one TensorInfo input needs to be provided.");
865  }
866  if (workloadInfo.m_OutputTensorInfos.size() <= 0)
867  {
868  throw InvalidArgumentException(descriptorName + ": At least one TensorInfo output needs to be provided.");
869  }
870 
871  if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
872  {
873  throw InvalidArgumentException(descriptorName + ": Invalid concatenation axis provided.");
874  }
875 
876  if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
877  {
878  return;
879  }
880 
881  if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
882  {
884  descriptorName + ": Number of split windows "
885  "has to match number of workloadInfo.m_InputTensorInfos. "
886  "Number of windows: " +
887  to_string(m_ViewOrigins.size()) +
888  ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
889  }
890 
891  //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
892  std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
893  for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
894  {
895  //Checks that the dimensionality of output is same as the split windows.
896  ViewOrigin const& e = m_ViewOrigins[w];
897  if (e.m_Origin.size() != outputDims)
898  {
899  throw InvalidArgumentException(descriptorName + ": Window origin have to "
900  "have the same dimensionality as the output tensor. "
901  "Window origin (index: " +
902  to_string(w) + ") has " + to_string(e.m_Origin.size()) +
903  " dimensions, the output "
904  "tensor has " +
905  to_string(outputDims) + " dimensions.");
906  }
907  //Checks that the merge windows are within the output tensor.
908  for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
909  {
910  if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
911  > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
912  {
913  throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
914  "be smaller or equal than the size of the output in that coord.");
915  }
916  }
917  }
918 
919  // Check the supported data types
920  std::vector<DataType> supportedTypes =
921  {
930  };
931 
932  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
933  for (unsigned long i = 0ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
934  {
935  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[i];
936  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
937 
938  const std::string inputName = "input_" + std::to_string(i);
939  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, inputName, "output");
940  }
941 }
942 
943 void StackQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
944 {
945  const std::string descriptorName{"StackQueueDescriptor"};
946 
947  ValidateNumOutputs(workloadInfo, descriptorName, 1);
948 
949  if (m_Parameters.m_NumInputs != workloadInfo.m_InputTensorInfos.size())
950  {
951  throw InvalidArgumentException(descriptorName + ": Must have the defined number of input tensors.");
952  }
953 
954  // All inputs must have the same shape, which is defined in parameters
955  const TensorShape& inputShape = m_Parameters.m_InputShape;
956  for (unsigned int i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
957  {
958  if (workloadInfo.m_InputTensorInfos[i].GetShape() != inputShape)
959  {
960  throw InvalidArgumentException(descriptorName + ": All input tensor shapes must match the defined shape.");
961  }
962  }
963 
964  if (inputShape.GetNumDimensions() > 4)
965  {
966  throw InvalidArgumentException(descriptorName + ": Input tensor may have up to 4 dimensions.");
967  }
968 
969  // m_Axis is 0-based and may take values from 0 to the number of input dimensions (inclusive),
970  // since the output tensor has an additional dimension.
971  if (m_Parameters.m_Axis > inputShape.GetNumDimensions())
972  {
973  throw InvalidArgumentException(descriptorName + ": Axis may not be greater "
974  "than the number of input dimensions.");
975  }
976 
977  // Output shape must be as inferred from the input shape
978  const TensorShape& outputShape = workloadInfo.m_OutputTensorInfos[0].GetShape();
979  for (unsigned int i = 0; i < m_Parameters.m_Axis; ++i)
980  {
981  if (outputShape[i] != inputShape[i])
982  {
983  throw InvalidArgumentException(descriptorName + ": Output tensor must "
984  "match shape inferred from input tensor.");
985  }
986  }
987 
988  if (outputShape[m_Parameters.m_Axis] != m_Parameters.m_NumInputs)
989  {
990  throw InvalidArgumentException(descriptorName + ": Output tensor must "
991  "match shape inferred from input tensor.");
992  }
993 
994  for (unsigned int i = m_Parameters.m_Axis + 1; i < inputShape.GetNumDimensions() + 1; ++i)
995  {
996  if (outputShape[i] != inputShape[i-1])
997  {
998  throw InvalidArgumentException(descriptorName + ": Output tensor must "
999  "match shape inferred from input tensor.");
1000  }
1001  }
1002 
1003  if (outputShape.GetNumDimensions() > 5)
1004  {
1005  throw InvalidArgumentException(descriptorName + ": Output tensor may have up to 5 dimensions.");
1006  }
1007 
1008  // Check the supported data types
1009  std::vector<DataType> supportedTypes =
1010  {
1019  };
1020 
1021  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
1022 
1023  for (unsigned int i = 1ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
1024  {
1025  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1026  workloadInfo.m_InputTensorInfos[i],
1027  descriptorName,
1028  "input_0",
1029  "input_" + std::to_string(i));
1030  }
1031 
1032  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1033  workloadInfo.m_OutputTensorInfos[0],
1034  descriptorName,
1035  "input_0",
1036  "output");
1037 }
1038 
1039 void FillQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1040 {
1041  const std::string descriptorName{"FillQueueDescriptor"};
1042 
1043  ValidateNumInputs(workloadInfo, descriptorName, 1);
1044  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1045 
1046  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1047  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1048 
1049  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 1, "input");
1050 
1051  std::vector<DataType> supportedTypes =
1052  {
1057  };
1058 
1059  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1060 }
1061 
1063 {
1064  const std::string descriptorName{"FullyConnectedQueueDescriptor"};
1065 
1066  uint32_t numInputs = 2;
1067  if (m_Parameters.m_BiasEnabled)
1068  {
1069  numInputs = 3;
1070  }
1071 
1072  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1073  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1074 
1075  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1076  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1077 
1078  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1079 
1080  if (!(inputTensorInfo.GetNumDimensions() == 2 || inputTensorInfo.GetNumDimensions() == 4))
1081  {
1082  throw InvalidArgumentException(descriptorName + ": Input tensor must have 2 or 4 dimensions.");
1083  }
1084 
1085  TensorInfo weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1086  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 2, "weight");
1087 
1088  if (m_Parameters.m_BiasEnabled)
1089  {
1090  TensorInfo biasTensorInfo = workloadInfo.m_InputTensorInfos[2];
1091  // Validates type and quantization values.
1092  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1093  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1094  ValidateTensorNumDimensions(biasTensorInfo, descriptorName, 1, "bias");
1095  }
1096 
1097  // Check the supported data types
1098  std::vector<DataType> supportedTypes =
1099  {
1106  };
1107 
1108  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1109 
1110  // For FullyConnected, we allow to have BFloat16 input with Float32 output for optimization.
1111  if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1112  {
1113  if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1114  {
1115  throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1116  "for BFloat16 input.");
1117  }
1118  }
1119  else
1120  {
1121  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1122  }
1123 }
1124 
1126 {
1127  const std::string descriptorName{"NormalizationQueueDescriptor"};
1128 
1129  ValidateNumInputs(workloadInfo, descriptorName, 1);
1130  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1131 
1132  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1133  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1134 
1135  // Check the supported data types
1136  std::vector<DataType> supportedTypes =
1137  {
1144  };
1145 
1146  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1147 
1148  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1149 
1150  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1151 }
1152 
1153 void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1154 {
1155  const std::string descriptorName{"AdditionQueueDescriptor"};
1156 
1157  ValidateNumInputs(workloadInfo, descriptorName, 2);
1158  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1159 
1160  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1161  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1162  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1163 
1164  std::vector<DataType> supportedTypes =
1165  {
1173  };
1174 
1175  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1176  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1177  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1178 
1179  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1180  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1181 
1182  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1183  inputTensorInfo1,
1184  outputTensorInfo,
1185  descriptorName,
1186  "input_0",
1187  "input_1");
1188 }
1189 
1191 {
1192  const std::string descriptorName{"MultiplicationQueueDescriptor"};
1193 
1194  ValidateNumInputs(workloadInfo, descriptorName, 2);
1195  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1196 
1197  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1198  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1199  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1200 
1201  std::vector<DataType> supportedTypes =
1202  {
1210  };
1211 
1212  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1213  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1214  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1215 
1216  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1217  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1218 
1219  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1220  inputTensorInfo1,
1221  outputTensorInfo,
1222  descriptorName,
1223  "input_0",
1224  "input_1");
1225 }
1226 
1228 {
1229  const std::string descriptorName{"BatchNormalizationQueueDescriptor"};
1230 
1231  ValidateNumInputs(workloadInfo, descriptorName, 1);
1232  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1233 
1234  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1235  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1236 
1237  std::vector<DataType> supportedTypes =
1238  {
1245  };
1246 
1247  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1248  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1249 
1250  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1251  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1252 
1253  ValidatePointer(m_Mean, descriptorName, "mean");
1254  ValidatePointer(m_Variance, descriptorName, "variance");
1255  ValidatePointer(m_Beta, descriptorName, "beta");
1256  ValidatePointer(m_Gamma, descriptorName, "gamma");
1257 
1258  const TensorInfo& mean = m_Mean->GetTensorInfo();
1259  const TensorInfo& variance = m_Variance->GetTensorInfo();
1260  const TensorInfo& beta = m_Beta->GetTensorInfo();
1261  const TensorInfo& gamma = m_Gamma->GetTensorInfo();
1262 
1263  ValidateTensorNumDimensions(mean, descriptorName, 1, "mean");
1264  ValidateTensorNumDimensions(variance, descriptorName, 1, "variance");
1265  ValidateTensorNumDimensions(beta, descriptorName, 1, "beta");
1266  ValidateTensorNumDimensions(gamma, descriptorName, 1, "gamma");
1267 
1268  ValidateTensorShapesMatch(mean, variance, descriptorName, "mean", "variance");
1269  ValidateTensorShapesMatch(mean, beta, descriptorName, "mean", "beta");
1270  ValidateTensorShapesMatch(mean, gamma, descriptorName, "mean", "gamma");
1271 }
1272 
1274 {
1275  const std::string descriptorName{"Convolution2dQueueDescriptor"};
1276 
1277  uint32_t numInputs = 2;
1278  if (m_Parameters.m_BiasEnabled)
1279  {
1280  numInputs = 3;
1281  }
1282 
1283  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1284  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1285 
1286  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1287  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1288 
1289  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1290  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1291 
1292  const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1293 
1294  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1295 
1296  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1297 
1298  Optional<TensorInfo> optionalBiasTensorInfo;
1299  if (m_Parameters.m_BiasEnabled)
1300  {
1301  optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1302  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1303 
1304  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1305  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1306  }
1307 
1308  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1309  {
1311  fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1312  "cannot be either negative or 0.",
1313  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1314  }
1315 
1316  ValidatePerAxisQuantization(inputTensorInfo,
1317  outputTensorInfo,
1318  weightTensorInfo,
1319  optionalBiasTensorInfo,
1320  descriptorName);
1321 
1322  std::vector<DataType> supportedTypes =
1323  {
1331  };
1332 
1333  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1334 
1335  // For Convolution2d, we allow to have BFloat16 input with Float32 output for optimization.
1336  if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1337  {
1338  if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1339  {
1340  throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1341  "for BFloat16 input.");
1342  }
1343  }
1344  else
1345  {
1346  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1347  }
1348 }
1349 
1351 {
1352  const std::string descriptorName{"Convolution3dQueueDescriptor"};
1353 
1354  uint32_t numInputs = 2;
1355  if (m_Parameters.m_BiasEnabled)
1356  {
1357  numInputs = 3;
1358  }
1359  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1360  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1361 
1362  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1363  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1364 
1365  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 5, "input");
1366  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 5, "output");
1367 
1368  const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1369  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 5, "weight");
1370 
1371  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1372 
1373  Optional<TensorInfo> optionalBiasTensorInfo;
1374  if (m_Parameters.m_BiasEnabled)
1375  {
1376  optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1377  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1378 
1379  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1380  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1381  }
1382 
1383  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 || m_Parameters.m_StrideZ <= 0 )
1384  {
1386  fmt::format("{}: strideX (provided {}), strideY (provided {}) or strideZ (provided {})"
1387  "cannot be either negative or 0.",
1388  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY, m_Parameters.m_StrideZ));
1389  }
1390 
1391  ValidatePerAxisQuantization(inputTensorInfo,
1392  outputTensorInfo,
1393  weightTensorInfo,
1394  optionalBiasTensorInfo,
1395  descriptorName);
1396 
1397  std::vector<DataType> supportedTypes =
1398  {
1406  };
1407 
1408  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1409  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1410 }
1411 
1413 {
1414  const std::string descriptorName{"DepthwiseConvolution2dQueueDescriptor"};
1415 
1416  uint32_t numInputs = 2;
1417  if (m_Parameters.m_BiasEnabled)
1418  {
1419  numInputs = 3;
1420  }
1421 
1422  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1423  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1424 
1425  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1426  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1427 
1428  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1429  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1430 
1431  const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1432  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1433 
1434  if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 )
1435  {
1437  fmt::format("{}: dilationX (provided {}) and dilationY (provided {}) "
1438  "cannot be smaller than 1.",
1439  descriptorName, m_Parameters.m_DilationX, m_Parameters.m_DilationX));
1440  }
1441 
1442  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1443  {
1445  fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1446  "cannot be either negative or 0.",
1447  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1448  }
1449 
1450  if (weightTensorInfo.GetShape()[0] != 1)
1451  {
1452  throw InvalidArgumentException(fmt::format(
1453  "{0}: The weight format in armnn is expected to be [1, H, W, Cout]."
1454  "But first dimension is not equal to 1. Provided weight shape: [{1}, {2}, {3}, {4}]",
1455  descriptorName,
1456  weightTensorInfo.GetShape()[0],
1457  weightTensorInfo.GetShape()[1],
1458  weightTensorInfo.GetShape()[2],
1459  weightTensorInfo.GetShape()[3]));
1460  }
1461 
1462  const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
1463  const unsigned int numWeightOutputChannelsRefFormat = weightTensorInfo.GetShape()[3];
1464  const unsigned int numWeightOutputChannelsAclFormat = weightTensorInfo.GetShape()[1];
1465  const unsigned int numOutputChannels = outputTensorInfo.GetShape()[channelIndex];
1466 
1467  // Weights format has two valid options: [1, H, W, Cout] (CpuRef) or [1, Cout, H, W] (CpuAcc/GpuAcc).
1468  bool validRefFormat = (numWeightOutputChannelsRefFormat == numOutputChannels);
1469  bool validAclFormat = (numWeightOutputChannelsAclFormat == numOutputChannels);
1470 
1471  if (!(validRefFormat || validAclFormat))
1472  {
1473  throw InvalidArgumentException(fmt::format(
1474  "{0}: The weight format in armnn is expected to be [1, H, W, Cout] (CpuRef) or [1, Cout, H, W] "
1475  "(CpuAcc/GpuAcc). But neither the 4th (CpuRef) or 2nd (CpuAcc/GpuAcc) dimension is equal to Cout."
1476  "Cout = {1} Provided weight shape: [{2}, {3}, {4}, {5}]",
1477  descriptorName,
1478  numOutputChannels,
1479  weightTensorInfo.GetShape()[0],
1480  weightTensorInfo.GetShape()[1],
1481  weightTensorInfo.GetShape()[2],
1482  weightTensorInfo.GetShape()[3]));
1483  }
1484 
1485  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1486 
1487  Optional<TensorInfo> optionalBiasTensorInfo;
1488  if (m_Parameters.m_BiasEnabled)
1489  {
1490  optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1491  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1492 
1493  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1494  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1495  }
1496  ValidatePerAxisQuantization(inputTensorInfo,
1497  outputTensorInfo,
1498  weightTensorInfo,
1499  optionalBiasTensorInfo,
1500  descriptorName);
1501 
1502  std::vector<DataType> supportedTypes =
1503  {
1510  };
1511 
1512  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1513  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1514 }
1515 
1516 void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1517 {
1518  const std::string descriptorName{"PermuteQueueDescriptor"};
1519 
1520  ValidateNumInputs(workloadInfo, descriptorName, 1);
1521  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1522 
1523  const PermutationVector& mapping = m_Parameters.m_DimMappings;
1524 
1525  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1526  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1527 
1528  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
1529  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
1530 
1531  for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
1532  {
1533  if (inputTensorInfo.GetShape()[i] != outputTensorInfo.GetShape()[mapping[i]])
1534  {
1535  throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(i) +
1536  " (=" + to_string(inputTensorInfo.GetShape()[i]) + ") " +
1537  "must match dst dimension " + to_string(mapping[i]) +
1538  " (=" + to_string(outputTensorInfo.GetShape()[mapping[i]]) + ")");
1539  }
1540  }
1541 
1542  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1543 }
1544 
1545 void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1546 {
1547  const std::string descriptorName{"Pooling2dQueueDescriptor"};
1548 
1549  ValidateNumInputs(workloadInfo, descriptorName, 1);
1550  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1551 
1552  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1553  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1554 
1555  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1556  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1557 
1558  std::vector<DataType> supportedTypes =
1559  {
1566  };
1567 
1568  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1569  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1570 }
1571 
1572 void Pooling3dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1573 {
1574  const std::string descriptorName{"Pooling3dQueueDescriptor"};
1575 
1576  ValidateNumInputs(workloadInfo, descriptorName, 1);
1577  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1578 
1579  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1580  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1581 
1582  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 5, "input");
1583  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 5, "output");
1584 
1585  std::vector<DataType> supportedTypes =
1586  {
1593  };
1594 
1595  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1596  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1597 }
1598 
1599 void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1600 {
1601  const std::string descriptorName{"ResizeQueueDescriptor"};
1602 
1603  ValidateNumInputs(workloadInfo, descriptorName, 1);
1604  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1605 
1606  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1607  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1608 
1609  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1610  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1611 
1612  std::vector<DataType> supportedTypes =
1613  {
1620  };
1621 
1622  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1623  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1624 
1625  // Resize only changes width and height: batch and channel count must match.
1626  const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0];
1627  const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0];
1628  if (inputBatchSize != outputBatchSize)
1629  {
1631  fmt::format("{}: Input batch size ({}) does not match output batch size ({})",
1632  descriptorName, inputBatchSize, outputBatchSize));
1633  }
1634 
1635  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1636  const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1637  const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1638  if (inputChannelCount != outputChannelCount)
1639  {
1641  fmt::format("{}: Input channel count ({}) does not match output channel count ({})",
1642  descriptorName, inputChannelCount, outputChannelCount));
1643  }
1644 }
1645 
1647 {
1648  const std::string descriptorName{"FakeQuantizationQueueDescriptor"};
1649 
1650  ValidateNumInputs(workloadInfo, descriptorName, 1);
1651  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1652 
1653  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1654  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1655 
1656  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 2, "input");
1657  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1658 
1659  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1660 
1661  if (m_Parameters.m_Min > m_Parameters.m_Max)
1662  {
1663  throw InvalidArgumentException(descriptorName + ": min cannot be greater than max");
1664  }
1665 }
1666 
1668 {
1669  const std::string descriptorName{"InstanceNormalizationQueueDescriptor"};
1670 
1671  ValidateNumInputs(workloadInfo, descriptorName, 1);
1672  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1673 
1674  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1675  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1676 
1677  if (inputTensorInfo.GetNumDimensions() > 4)
1678  {
1679  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1680  }
1681 
1682  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1683 
1684  // Check the supported data types
1685  std::vector<DataType> supportedTypes =
1686  {
1690  };
1691 
1692  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1693  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1694 }
1695 
1697 {
1698  const std::string descriptorName{"L2NormalizationQueueDescriptor"};
1699 
1700  ValidateNumInputs(workloadInfo, descriptorName, 1);
1701  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1702 
1703  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1704  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1705 
1706  if (inputTensorInfo.GetNumDimensions() > 4)
1707  {
1708  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1709  }
1710 
1711  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1712 
1713  // Check the supported data types
1714  std::vector<DataType> supportedTypes =
1715  {
1722  };
1723 
1724  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1725  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1726 }
1727 
1728 void LogSoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1729 {
1730  const std::string descriptorName{"LogSoftmaxQueueDescriptor"};
1731 
1732  ValidateNumInputs(workloadInfo, descriptorName, 1);
1733  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1734 
1735  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1736  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1737 
1738  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1739 
1740  std::vector<DataType> supportedTypes =
1741  {
1745  };
1746 
1747  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1748  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1749 }
1750 
1751 void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1752 {
1753  const std::string descriptorName{"ConstantQueueDescriptor"};
1754 
1755  ValidateNumInputs(workloadInfo, descriptorName, 0);
1756  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1757 
1758  if (!m_LayerOutput)
1759  {
1760  throw InvalidArgumentException(descriptorName + ": No const input specified.");
1761  }
1762 
1763  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1764  ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(), outputTensorInfo, descriptorName, "constant", "output");
1765 
1766  // Check the supported data types
1767  std::vector<DataType> supportedTypes =
1768  {
1777  };
1778 
1779  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1780 }
1781 
1782 void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1783 {
1784  const std::string descriptorName{"ReshapeQueueDescriptor"};
1785 
1786  ValidateNumInputs(workloadInfo, descriptorName, 1);
1787  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1788 
1789  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1790  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1791 
1792  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1793 
1794  // Check the supported data types
1795  std::vector<DataType> supportedTypes =
1796  {
1805  };
1806 
1807  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1808  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1809 }
1810 
1812 {
1813  const std::string descriptorName{"SpaceToBatchNdQueueDescriptor"};
1814 
1815  ValidateNumInputs(workloadInfo, descriptorName, 1);
1816  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1817 
1818  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1819  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1820 
1821  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1822  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1823 
1824  if (m_Parameters.m_BlockShape.size() != 2)
1825  {
1826  throw InvalidArgumentException(descriptorName + ": Block Shape must contain 2 spatial dimensions.");
1827  }
1828 
1829  if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
1830  {
1831  throw InvalidArgumentException(descriptorName + ": Pad List must contain the same number of "
1832  "dimensions as Block Shape.");
1833  }
1834 
1835  const TensorShape& inputShape = inputTensorInfo.GetShape();
1836 
1837  std::pair<unsigned int, unsigned int> heightPad = m_Parameters.m_PadList[0];
1838  std::pair<unsigned int, unsigned int> widthPad = m_Parameters.m_PadList[1];
1839 
1840  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1841 
1842  const unsigned int inputWidth = inputShape[dimensionIndices.GetWidthIndex()] +
1843  widthPad.first + widthPad.second;
1844  const unsigned int inputHeight = inputShape[dimensionIndices.GetHeightIndex()] +
1845  heightPad.first + heightPad.second;
1846 
1847  const unsigned int numInputElements = inputShape[0] * inputHeight * inputWidth *
1848  inputShape[dimensionIndices.GetChannelsIndex()];
1849  const unsigned int numOutputElements = outputTensorInfo.GetNumElements();
1850 
1851  if (numOutputElements != numInputElements)
1852  {
1853  throw InvalidArgumentException(descriptorName + ": Input tensor has " +
1854  to_string(numInputElements) + " after padding but output tensor has " +
1855  to_string(numOutputElements) + " elements.");
1856  }
1857 
1858  if (inputHeight % m_Parameters.m_BlockShape[0] != 0 || inputWidth % m_Parameters.m_BlockShape[1] != 0)
1859  {
1860  throw InvalidArgumentException(descriptorName + ": Input shape after padding must be "
1861  "divisible by Block Shape in all spatial dimensions");
1862  }
1863 
1864  std::vector<DataType> supportedTypes =
1865  {
1872  };
1873 
1874  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1875  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1876 }
1877 
1879 {
1880  const std::string descriptorName{"SpaceToDepthQueueDescriptor"};
1881 
1882  ValidateNumInputs(workloadInfo, descriptorName, 1);
1883  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1884 
1885  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1886  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1887 
1888  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1889  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1890 
1891  std::vector<DataType> supportedTypes =
1892  {
1899  };
1900 
1901  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1902  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1903 
1904  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1905 
1906  if (m_Parameters.m_BlockSize == 0)
1907  {
1908  throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
1909  }
1910 
1911  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1912  const unsigned int wIndex = dimensionIndices.GetWidthIndex();
1913  const unsigned int hIndex = dimensionIndices.GetHeightIndex();
1914  const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
1915 
1916  const TensorShape& inputShape = inputTensorInfo.GetShape();
1917  if (inputShape[hIndex] % m_Parameters.m_BlockSize != 0 || inputShape[wIndex] % m_Parameters.m_BlockSize != 0)
1918  {
1919  throw InvalidArgumentException(descriptorName + ": Input shape must be divisible "
1920  "by block size in all spatial dimensions");
1921  }
1922 
1923  const TensorShape& outputShape = outputTensorInfo.GetShape();
1924  if (outputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
1925  {
1926  throw InvalidArgumentException(descriptorName + ": The depth of the output tensor"
1927  "must be divisible by the square of block size." );
1928  }
1929 }
1930 
1931 void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1932 {
1933  const std::string descriptorName{"FloorQueueDescriptor"};
1934 
1935  ValidateNumInputs(workloadInfo, descriptorName, 1);
1936  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1937 
1938  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1939  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1940 
1941  std::vector<DataType> supportedTypes =
1942  {
1947  };
1948 
1949  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1950  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1951  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1952  ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1953 }
1954 
1955 void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1956 {
1957  // ported from android/ml/nn/common/operations/LSTM.cpp CheckInputTensorDimensions()
1958 
1959  const std::string descriptorName{"LstmQueueDescriptor"};
1960 
1961  // check dimensions of all inputs and outputs
1962  if (workloadInfo.m_InputTensorInfos.size() != 3)
1963  {
1964  throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
1965  }
1966  if (workloadInfo.m_OutputTensorInfos.size() != 4)
1967  {
1968  throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
1969  }
1970 
1971  std::vector<DataType> supportedTypes =
1972  {
1977  };
1978 
1979  // check for supported type of one input and match them with all the other input and output
1980  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
1981 
1982  // type matches all other inputs
1983  for (uint32_t i = 1u; i < workloadInfo.m_InputTensorInfos.size(); ++i)
1984  {
1985  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1986  workloadInfo.m_InputTensorInfos[i],
1987  descriptorName,
1988  "input_0",
1989  "input_" + std::to_string(i));
1990  }
1991  // type matches all other outputs
1992  for (uint32_t i = 0u; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
1993  {
1994  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1995  workloadInfo.m_OutputTensorInfos[i],
1996  "LstmQueueDescriptor",
1997  "input_0",
1998  "output_" + std::to_string(i));
1999  }
2000 
2001  // Making sure clipping parameters have valid values.
2002  // == 0 means no clipping
2003  // > 0 means clipping
2004  if (m_Parameters.m_ClippingThresCell < 0.0f)
2005  {
2006  throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
2007  }
2008  if (m_Parameters.m_ClippingThresProj < 0.0f)
2009  {
2010  throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
2011  }
2012 
2013  // Inferring batch size, number of outputs and number of cells from the inputs.
2014  const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[1];
2015  const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
2016  ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
2017  const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
2018  ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
2019  const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
2020 
2021  // input tensor
2022  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 2, (n_batch * n_input),
2023  descriptorName + " input_0");
2024  // outputStateInTensor
2025  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
2026  descriptorName + " input_1");
2027  // outputStateInTensor
2028  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
2029  descriptorName + " input_2");
2030  // scratchBufferTensor
2031  unsigned int scratchBufferSize = m_Parameters.m_CifgEnabled ? n_cell * 3 : n_cell * 4;
2032  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[0], 2, (n_batch * scratchBufferSize),
2033  descriptorName + " output_0");
2034  // outputStateOutTensor
2035  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[1], 2, (n_batch * n_output),
2036  descriptorName + " output_1");
2037  // cellStateOutTensor
2038  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 2, (n_batch * n_cell),
2039  descriptorName + " output_2");
2040  // outputTensor
2041  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[3], 2, (n_batch * n_output),
2042  descriptorName + " output_3");
2043 
2044  // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
2045  if ( m_InputToInputWeights )
2046  {
2047  ValidateTensorNumDimNumElem(m_InputToInputWeights->GetTensorInfo(), 2,
2048  (n_cell * n_input), "InputLayerNormWeights");
2049  }
2050 
2051  ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
2052  ValidateTensorNumDimNumElem(m_InputToForgetWeights->GetTensorInfo(), 2,
2053  (n_cell * n_input), "InputToForgetWeights");
2054 
2055  ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
2056  ValidateTensorNumDimNumElem(m_InputToCellWeights->GetTensorInfo(), 2,
2057  (n_cell * n_input), "InputToCellWeights");
2058 
2059  if ( m_RecurrentToInputWeights )
2060  {
2061  ValidateTensorNumDimNumElem(m_RecurrentToInputWeights->GetTensorInfo(), 2,
2062  (n_cell * n_output), "RecurrentToInputWeights");
2063  }
2064 
2065  ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
2066  ValidateTensorNumDimNumElem(m_RecurrentToForgetWeights->GetTensorInfo(), 2,
2067  (n_cell * n_output), "RecurrentToForgetWeights");
2068 
2069  ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
2070  ValidateTensorNumDimNumElem(m_RecurrentToCellWeights->GetTensorInfo(), 2,
2071  (n_cell * n_output), "RecurrentToCellWeights");
2072 
2073  // Make sure the input-gate's parameters are either both present (regular
2074  // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
2075  bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
2076  !m_Parameters.m_CifgEnabled) ||
2077  (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
2078  m_Parameters.m_CifgEnabled));
2079  if (!cifg_weights_all_or_none)
2080  {
2081  throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
2082  "RecurrentToInputWeights must either both be present (regular LSTM) "
2083  "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
2084  "accordingly.");
2085  }
2086 
2087  if ( m_CellToInputWeights )
2088  {
2089  ValidateTensorNumDimNumElem(m_CellToInputWeights->GetTensorInfo(), 1,
2090  n_cell, "CellToInputWeights");
2091  }
2092  if ( m_CellToForgetWeights )
2093  {
2094  ValidateTensorNumDimNumElem(m_CellToForgetWeights->GetTensorInfo(), 1,
2095  n_cell, "CellToForgetWeights");
2096  }
2097  if ( m_CellToOutputWeights )
2098  {
2099  ValidateTensorNumDimNumElem(m_CellToOutputWeights->GetTensorInfo(), 1,
2100  n_cell, "CellToOutputWeights");
2101  }
2102 
2103  // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
2104  bool peephole_weights_all_or_none =
2105  (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
2106  && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
2107  || ( !m_CellToInputWeights && !m_CellToForgetWeights
2108  && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
2109  if (!peephole_weights_all_or_none)
2110  {
2111  throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
2112  }
2113 
2114  // Make sure the input gate bias is present only when not a CIFG-LSTM.
2115  if (m_Parameters.m_CifgEnabled)
2116  {
2117  if (m_InputGateBias)
2118  {
2119  throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
2120  }
2121  }
2122  else
2123  {
2124  if (!m_InputGateBias)
2125  {
2126  throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
2127  "must be present.");
2128  }
2129  ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1,
2130  n_cell, "InputGateBias");
2131  }
2132 
2133  ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
2134  ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
2135 
2136  ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
2137  ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
2138 
2139  ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
2140  ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
2141 
2142  if (m_ProjectionWeights)
2143  {
2144  ValidateTensorNumDimNumElem(m_ProjectionWeights->GetTensorInfo(), 2,
2145  (n_cell * n_output), "ProjectionWeights");
2146  }
2147  if (m_ProjectionBias)
2148  {
2149  ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
2150  }
2151 
2152  // Making sure the projection tensors are consistent:
2153  // 1) If projection weight is not present, then projection bias should not be
2154  // present.
2155  // 2) If projection weight is present, then projection bias is optional.
2156  bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
2157  !m_Parameters.m_ProjectionEnabled)
2158  || (m_ProjectionWeights && !m_ProjectionBias &&
2159  m_Parameters.m_ProjectionEnabled)
2160  || (m_ProjectionWeights && m_ProjectionBias &&
2161  m_Parameters.m_ProjectionEnabled));
2162  if (!projecton_tensors_consistent)
2163  {
2164  throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
2165  }
2166 
2167  // The four layer normalization weights either all have values or none of them have values. Additionally, if
2168  // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
2169  // either all have values or none of them have values. Layer normalization is used when the values of all the
2170  // layer normalization weights are present
2171  if (m_InputLayerNormWeights)
2172  {
2173  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
2174  }
2175  if (m_ForgetLayerNormWeights)
2176  {
2177  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2178  }
2179  if (m_CellLayerNormWeights)
2180  {
2181  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2182  }
2183  if (m_OutputLayerNormWeights)
2184  {
2185  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2186  }
2187 
2188  if (m_Parameters.m_LayerNormEnabled)
2189  {
2190  if (!m_Parameters.m_CifgEnabled)
2191  {
2192  if (!m_InputLayerNormWeights)
2193  {
2194  throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
2195  "disabled but InputLayerNormWeights are not present");
2196  }
2197  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(),
2198  1, n_cell, "InputLayerNormWeights");
2199  }
2200  else if (m_InputLayerNormWeights)
2201  {
2202  throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
2203  "enabled");
2204  }
2205 
2206  ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
2207  "ForgetLayerNormWeights");
2208  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2209 
2210  ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
2211  "OutputLayerNormWeights");
2212  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2213 
2214  ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
2215  "CellLayerNormWeights");
2216  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2217  }
2218  else if (m_InputLayerNormWeights || m_ForgetLayerNormWeights || m_OutputLayerNormWeights || m_CellLayerNormWeights)
2219  {
2220  throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
2221  "normalisation weights are present.");
2222  }
2223 }
2224 
2226 {
2227  const std::string descriptorName{"ConvertBf16ToFp32QueueDescriptor"};
2228 
2229  ValidateNumInputs(workloadInfo, descriptorName, 1);
2230  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2231 
2232  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2233  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2234 
2235  if (inputTensorInfo.GetDataType() != DataType::BFloat16)
2236  {
2237  throw InvalidArgumentException(descriptorName + ": Input tensor type must be BFloat16.");
2238  }
2239 
2240  if (outputTensorInfo.GetDataType() != DataType::Float32)
2241  {
2242  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32.");
2243  }
2244 
2245  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2246 }
2247 
2249 {
2250  const std::string descriptorName{"ConvertFp32ToBf16QueueDescriptor"};
2251 
2252  ValidateNumInputs(workloadInfo, descriptorName, 1);
2253  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2254 
2255  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2256  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2257 
2258  if (inputTensorInfo.GetDataType() != DataType::Float32)
2259  {
2260  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32.");
2261  }
2262 
2263  if (outputTensorInfo.GetDataType() != DataType::BFloat16)
2264  {
2265  throw InvalidArgumentException(descriptorName + ": Output tensor type must be BFloat16.");
2266  }
2267 
2268  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2269 }
2270 
2272 {
2273  const std::string descriptorName{"ConvertFp32ToFp16QueueDescriptor"};
2274 
2275  ValidateNumInputs(workloadInfo, descriptorName, 1);
2276  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2277 
2278  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2279  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2280 
2281  if (inputTensorInfo.GetDataType() != DataType::Float32)
2282  {
2283  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32.");
2284  }
2285 
2286  if (outputTensorInfo.GetDataType() != DataType::Float16)
2287  {
2288  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float16.");
2289  }
2290 
2291  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2292 }
2293 
2295 {
2296  const std::string descriptorName{"ConvertFp16ToFp32QueueDescriptor"};
2297 
2298  ValidateNumInputs(workloadInfo, descriptorName, 1);
2299  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2300 
2301  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2302  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2303 
2304  if (inputTensorInfo.GetDataType() != DataType::Float16)
2305  {
2306  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float16.");
2307  }
2308 
2309  if (outputTensorInfo.GetDataType() != DataType::Float32)
2310  {
2311  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32.");
2312  }
2313 
2314  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2315 }
2316 
2317 void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2318 {
2319  const std::string descriptorName{"DivisionQueueDescriptor"};
2320 
2321  ValidateNumInputs(workloadInfo, descriptorName, 2);
2322  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2323 
2324  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2325  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2326  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2327 
2328  std::vector<DataType> supportedTypes =
2329  {
2337  };
2338 
2339  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2340  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2341  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2342 
2343  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2344  inputTensorInfo1,
2345  outputTensorInfo,
2346  descriptorName,
2347  "input_0",
2348  "input_1");
2349 }
2350 
2352 {
2353  const std::string descriptorName{"SubtractionQueueDescriptor"};
2354 
2355  ValidateNumInputs(workloadInfo, descriptorName, 2);
2356  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2357 
2358  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2359  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2360  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2361 
2362  std::vector<DataType> supportedTypes =
2363  {
2371  };
2372 
2373  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2374  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2375  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2376 
2377  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2378  inputTensorInfo1,
2379  outputTensorInfo,
2380  descriptorName,
2381  "input_0",
2382  "input_1");
2383 }
2384 
2385 void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2386 {
2387  const std::string descriptorName{"MaximumQueueDescriptor"};
2388 
2389  ValidateNumInputs(workloadInfo, descriptorName, 2);
2390  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2391 
2392  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2393  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2394  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2395 
2396  std::vector<DataType> supportedTypes =
2397  {
2405  };
2406 
2407  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2408  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2409  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2410 
2411  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2412  inputTensorInfo1,
2413  outputTensorInfo,
2414  descriptorName,
2415  "input_0",
2416  "input_1");
2417 }
2418 
2419 void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2420 {
2421  const std::string descriptorName{"MeanQueueDescriptor"};
2422 
2423  ValidateNumInputs(workloadInfo, descriptorName, 1);
2424  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2425 
2426  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2427  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2428 
2429  std::vector<DataType> supportedTypes =
2430  {
2437  };
2438 
2439  // First check if input tensor data type is supported, then
2440  // check if this data type matches the output tensor data type
2441  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2442  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2443 
2444  if (m_Parameters.m_KeepDims)
2445  {
2446  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2447  }
2448  else if (m_Parameters.m_Axis.empty())
2449  {
2450  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
2451  }
2452  else
2453  {
2454  unsigned int outputDim =
2455  inputTensorInfo.GetNumDimensions() - armnn::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
2456  ValidateTensorNumDimensions(outputTensorInfo,
2457  descriptorName,
2458  outputDim > 0 ? outputDim : 1,
2459  "output");
2460  }
2461 }
2462 
2463 void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2464 {
2465  const std::string descriptorName{"PadQueueDescriptor"};
2466 
2467  ValidateNumInputs(workloadInfo, descriptorName, 1);
2468  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2469 
2470  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2471  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2472 
2473  // input and output should have the same number of dimensions
2474  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2475 
2476  // there should be entry in the pad list for each dimension in the input tensor
2477  if (m_Parameters.m_PadList.size() != inputTensorInfo.GetNumDimensions()) {
2478  throw InvalidArgumentException(descriptorName + ":Pad List should contain the same number of entries "
2479  "as there are dimensions in the input tensor that is " +
2480  std::to_string(inputTensorInfo.GetNumDimensions()) + " entries " +
2481  " not " + std::to_string(m_Parameters.m_PadList.size()) + " entries.");
2482  }
2483 }
2484 
2485 void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2486 {
2487  const std::string descriptorName{"QuantizeQueueDescriptor"};
2488 
2489  ValidateNumInputs(workloadInfo, descriptorName, 1);
2490  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2491 
2492  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2493  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2494 
2495  std::vector<DataType> supportedTypes =
2496  {
2504  };
2505 
2506  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2507 
2508  if (!IsQuantizedType(outputTensorInfo.GetDataType()))
2509  {
2510  throw InvalidArgumentException(descriptorName + ": Output of quantized layer must be quantized type.");
2511  }
2512 }
2513 
2515 {
2516  const std::string descriptorName{"BatchToSpaceNdQueueDescriptor"};
2517 
2518  ValidateNumInputs(workloadInfo, descriptorName, 1);
2519  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2520 
2521  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2522  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2523 
2524  std::vector<DataType> supportedTypes =
2525  {
2532  };
2533 
2534  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2535  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2536 }
2537 
2539 {
2540  const std::string descriptorName{"StridedSliceQueueDescriptor"};
2541 
2542  ValidateNumInputs(workloadInfo, descriptorName, 1);
2543  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2544 
2545  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2546  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2547 
2548  std::vector<DataType> supportedTypes =
2549  {
2556  };
2557 
2558  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2559  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2560 
2561  ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2562 
2563  const uint32_t rank = inputTensorInfo.GetNumDimensions();
2564  if (rank > 4)
2565  {
2566  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
2567  }
2568 
2569  // Begin, End & Stride length must be of rank(input0)
2570  if (m_Parameters.m_Begin.size() != rank)
2571  {
2572  throw InvalidArgumentException(descriptorName + ": Begin length must be of rank " + std::to_string(rank));
2573  }
2574 
2575  if (m_Parameters.m_End.size() != rank)
2576  {
2577  throw InvalidArgumentException(descriptorName + ": End length must be of rank " + std::to_string(rank));
2578  }
2579 
2580  if (m_Parameters.m_Stride.size() != rank)
2581  {
2582  throw InvalidArgumentException(descriptorName + ": Stride length must be of rank " + std::to_string(rank));
2583  }
2584 
2585  // Stride entries must be non-zero
2586  for (auto& stride : m_Parameters.m_Stride)
2587  {
2588  if (stride == 0)
2589  {
2590  throw InvalidArgumentException(descriptorName + ": Stride entries must be non-zero.");
2591  }
2592  }
2593 }
2594 
2595 void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2596 {
2597  const std::string descriptorName{"MinimumQueueDescriptor"};
2598 
2599  ValidateNumInputs(workloadInfo, descriptorName, 2);
2600  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2601 
2602  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2603  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2604  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2605 
2606  std::vector<DataType> supportedTypes =
2607  {
2615  };
2616 
2617  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2618  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2619  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2620 
2621  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2622  inputTensorInfo1,
2623  outputTensorInfo,
2624  descriptorName,
2625  "input_0",
2626  "input_1");
2627 }
2628 
2629 void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2630 {
2631  const std::string descriptorName{"DebugQueueDescriptor"};
2632 
2633  ValidateNumInputs(workloadInfo, descriptorName, 1);
2634  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2635 }
2636 
2637 void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2638 {
2639  const std::string descriptorName{"EqualQueueDescriptor"};
2640 
2641  ValidateNumInputs(workloadInfo, descriptorName, 2);
2642  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2643 
2644  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2645  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2646  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2647 
2648  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2649  inputTensorInfo1,
2650  outputTensorInfo,
2651  descriptorName,
2652  "input_0",
2653  "input_1");
2654 
2655  if (outputTensorInfo.GetDataType() != DataType::Boolean)
2656  {
2657  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2658  }
2659 }
2660 
2661 void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2662 {
2663  const std::string descriptorName{"GreaterQueueDescriptor"};
2664 
2665  ValidateNumInputs(workloadInfo, descriptorName, 2);
2666  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2667 
2668  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2669  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2670  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2671 
2672  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2673  inputTensorInfo1,
2674  outputTensorInfo,
2675  descriptorName,
2676  "input_0",
2677  "input_1");
2678 
2679  if (outputTensorInfo.GetDataType() != DataType::Boolean)
2680  {
2681  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2682  }
2683 }
2684 
2685 void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2686 {
2687  const std::string descriptorName{"RsqrtQueueDescriptor"};
2688 
2689  ValidateNumInputs(workloadInfo, descriptorName, 1);
2690  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2691 
2692  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2693  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2694 
2695  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2696 
2697  std::vector<DataType> supportedTypes =
2698  {
2705  };
2706 
2707  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2708  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2709 }
2710 
2711 void GatherNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2712 {
2713  const std::string descriptorName{"GatherNdQueueDescriptor"};
2714 
2715  ValidateNumInputs(workloadInfo, descriptorName, 2);
2716  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2717 
2718  const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1];
2719  if (indicesTensorInfo.GetDataType() != DataType::Signed32)
2720  {
2721  throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32.");
2722  }
2723 
2724  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2725  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2726 
2727  std::vector<DataType> supportedTypes =
2728  {
2736  };
2737 
2738  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2739 
2740  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2741 
2742  unsigned int outputDim = outputTensorInfo.GetNumDimensions();
2743  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output");
2744 }
2745 
2746 void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2747 {
2748  const std::string descriptorName{"GatherQueueDescriptor"};
2749 
2750  ValidateNumInputs(workloadInfo, descriptorName, 2);
2751  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2752 
2753  const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1];
2754  if (indicesTensorInfo.GetDataType() != DataType::Signed32)
2755  {
2756  throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32.");
2757  }
2758 
2759  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2760  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2761 
2762  std::vector<DataType> supportedTypes =
2763  {
2771  };
2772 
2773  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2774 
2775  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2776 
2777  unsigned int outputDim = inputTensorInfo.GetNumDimensions() + indicesTensorInfo.GetNumDimensions() - 1;
2778  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output");
2779 }
2780 
2782 {
2783  const std::string& descriptorName{"DetectionPostProcessQueueDescriptor"};
2784 
2785  ValidateNumInputs(workloadInfo, descriptorName, 2);
2786 
2787  if (workloadInfo.m_OutputTensorInfos.size() != 4)
2788  {
2789  throw InvalidArgumentException(descriptorName + ": Requires exactly four outputs. " +
2790  to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
2791  }
2792 
2793  if (m_Anchors == nullptr)
2794  {
2795  throw InvalidArgumentException(descriptorName + ": Anchors tensor descriptor is missing.");
2796  }
2797 
2798  const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
2799  const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
2800  const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
2801 
2802  const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
2803  const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
2804  const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
2805  const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
2806 
2807  ValidateTensorNumDimensions(boxEncodingsInfo, descriptorName, 3, "box encodings");
2808  ValidateTensorNumDimensions(scoresInfo, descriptorName, 3, "scores");
2809  ValidateTensorNumDimensions(anchorsInfo, descriptorName, 2, "anchors");
2810 
2811  const std::vector<DataType> supportedInputTypes =
2812  {
2819  };
2820 
2821  ValidateDataTypes(boxEncodingsInfo, supportedInputTypes, descriptorName);
2822  ValidateDataTypes(scoresInfo, supportedInputTypes, descriptorName);
2823  ValidateDataTypes(anchorsInfo, supportedInputTypes, descriptorName);
2824 
2825  ValidateTensorNumDimensions(detectionBoxesInfo, descriptorName, 3, "detection boxes");
2826  ValidateTensorNumDimensions(detectionScoresInfo, descriptorName, 2, "detection scores");
2827  ValidateTensorNumDimensions(detectionClassesInfo, descriptorName, 2, "detection classes");
2828  ValidateTensorNumDimensions(numDetectionsInfo, descriptorName, 1, "num detections");
2829 
2830  // NOTE: Output is always Float32 regardless of input type
2831  ValidateTensorDataType(detectionBoxesInfo, DataType::Float32, descriptorName, "detection boxes");
2832  ValidateTensorDataType(detectionScoresInfo, DataType::Float32, descriptorName, "detection scores");
2833  ValidateTensorDataType(detectionClassesInfo, DataType::Float32, descriptorName, "detection classes");
2834  ValidateTensorDataType(numDetectionsInfo, DataType::Float32, descriptorName, "num detections");
2835 
2836  if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f)
2837  {
2838  throw InvalidArgumentException(descriptorName + ": Intersection over union threshold "
2839  "must be positive and less than or equal to 1.");
2840  }
2841 
2842  if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
2843  {
2844  throw InvalidArgumentException(descriptorName + ": Number of classes with background "
2845  "should be equal to number of classes + 1.");
2846  }
2847 }
2848 
2849 void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2850 {
2851  const std::string& descriptorName{"DequantizeQueueDescriptor"};
2852 
2853  ValidateNumInputs(workloadInfo, descriptorName, 1);
2854  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2855 
2856  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2857  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2858 
2859  std::vector<DataType> inputSupportedTypes =
2860  {
2866  };
2867  ValidateDataTypes(inputTensorInfo, inputSupportedTypes, descriptorName);
2868 
2869  std::vector<DataType> outputSupportedTypes =
2870  {
2873  DataType::Float16
2874  };
2875 
2876  ValidateDataTypes(outputTensorInfo, outputSupportedTypes, descriptorName);
2877 }
2878 
2879 void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2880 {
2881  const std::string& descriptorName{"MergeQueueDescriptor"};
2882 
2883  ValidateNumInputs(workloadInfo, descriptorName, 2);
2884  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2885 
2886  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2887  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2888  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2889 
2890  ValidateTensorShapesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2891  ValidateTensorShapesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2892 
2893  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2894  ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2895 }
2896 
2897 void ShapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2898 {
2899  const std::string& descriptorName{"ShapeQueueDescriptor"};
2900 
2901  ValidateNumInputs(workloadInfo, descriptorName, 1);
2902  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2903 
2904  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2905  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2906 
2907  std::vector<DataType> supportedTypes =
2908  {
2918  };
2919 
2920  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2921  ValidateDataTypes(outputTensorInfo, {DataType::Signed32}, descriptorName);
2922 }
2923 
2924 void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2925 {
2926  const std::string& descriptorName{"SwitchQueueDescriptor"};
2927 
2928  ValidateNumInputs(workloadInfo, descriptorName, 2);
2929  ValidateNumOutputs(workloadInfo, descriptorName, 2);
2930 
2931  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2932  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2933 
2934  const TensorInfo& outputTensorInfo0 = workloadInfo.m_OutputTensorInfos[0];
2935  const TensorInfo& outputTensorInfo1 = workloadInfo.m_OutputTensorInfos[1];
2936 
2937  std::vector<DataType> supportedTypes =
2938  {
2944  };
2945 
2946  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2947  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2948 
2949  ValidateDataTypes(outputTensorInfo0, supportedTypes, descriptorName);
2950  ValidateDataTypes(outputTensorInfo1, supportedTypes, descriptorName);
2951 
2952  ValidateTensorShapesMatch(inputTensorInfo0,
2953  outputTensorInfo0,
2954  descriptorName,
2955  "input_0",
2956  "output_0");
2957 
2958  ValidateTensorShapesMatch(inputTensorInfo0,
2959  outputTensorInfo1,
2960  descriptorName,
2961  "input_0",
2962  "output_1");
2963 }
2964 
2965 void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& /*workloadInfo*/) const
2966 {
2967  // This is internally generated so it should not need validation.
2968 }
2969 
2970 void PreluQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2971 {
2972  const std::string& descriptorName{"PreluQueueDescriptor"};
2973 
2974  ValidateNumInputs(workloadInfo, descriptorName, 2);
2975  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2976 
2977  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2978  const TensorInfo& alphaTensorInfo = workloadInfo.m_InputTensorInfos[1];
2979  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2980 
2981  std::vector<DataType> supportedTypes
2982  {
2989  };
2990 
2991  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2992  ValidateDataTypes(alphaTensorInfo, supportedTypes, descriptorName);
2993 
2994  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2995 
2996  ValidateTensorDataTypesMatch(inputTensorInfo, alphaTensorInfo, descriptorName, "input", "alpha");
2997  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "ouptut");
2998 
2999  ValidateBroadcastTensorShapesMatch(inputTensorInfo,
3000  alphaTensorInfo,
3001  outputTensorInfo,
3002  descriptorName,
3003  "input",
3004  "alpha");
3005 }
3006 
3008 {
3009  const std::string descriptorName{"TransposeConvolution2dQueueDescriptor"};
3010 
3011  ValidateNumInputs(workloadInfo, descriptorName, 1);
3012  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3013 
3014  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3015  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3016 
3017  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
3018  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
3019 
3020  ValidatePointer(m_Weight, descriptorName, "weight");
3021 
3022  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
3023  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
3024 
3025  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
3026 
3027  Optional<TensorInfo> optionalBiasTensorInfo;
3028  if (m_Parameters.m_BiasEnabled)
3029  {
3030  ValidatePointer(m_Bias, descriptorName, "bias");
3031 
3032  optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
3033  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
3034 
3035  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
3036  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
3037  }
3038 
3039  ValidatePerAxisQuantization(inputTensorInfo,
3040  outputTensorInfo,
3041  weightTensorInfo,
3042  optionalBiasTensorInfo,
3043  descriptorName);
3044 
3045  std::vector<DataType> supportedTypes =
3046  {
3053  };
3054 
3055  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3056  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3057 }
3058 
3059 void TransposeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3060 {
3061  const std::string descriptorName{"TransposeQueueDescriptor"};
3062 
3063  ValidateNumInputs(workloadInfo, descriptorName, 1);
3064  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3065 
3066  const PermutationVector& mapping = m_Parameters.m_DimMappings;
3067 
3068  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3069  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3070 
3071  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
3072  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
3073 
3074  for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
3075  {
3076  if (inputTensorInfo.GetShape()[mapping[i]] != outputTensorInfo.GetShape()[i])
3077  {
3078  throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(mapping[i]) +
3079  " (=" + to_string(inputTensorInfo.GetShape()[mapping[i]]) + ") " +
3080  "must match dst dimension " + to_string(i) +
3081  " (=" + to_string(outputTensorInfo.GetShape()[i]) + ")");
3082  }
3083  }
3084 
3085  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3086 }
3087 
3089 {
3090  const std::string descriptorName{"TransposeQueueDescriptor"};
3091 
3092  ValidateNumInputs(workloadInfo, descriptorName, 1);
3093  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3094 
3095  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3096  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3097 
3098  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3099 }
3100 
3101 void QLstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3102 {
3103  const std::string descriptorName{"QLstmQueueDescriptor"};
3104 
3105  // Validate number of inputs/outputs
3106  ValidateNumInputs(workloadInfo, descriptorName, 3);
3107  ValidateNumOutputs(workloadInfo, descriptorName, 3);
3108 
3109  // Input/output tensor info
3110  auto inputInfo = workloadInfo.m_InputTensorInfos[0];
3111  auto outputStateInInfo = workloadInfo.m_InputTensorInfos[1];
3112  auto cellStateInInfo = workloadInfo.m_InputTensorInfos[2];
3113 
3114  auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
3115  auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
3116  auto outputInfo = workloadInfo.m_OutputTensorInfos[2];
3117 
3118  // Supported types for various tensors in QLSTM
3119  std::vector<DataType> inputOutputSupportedTypes =
3120  {
3122  };
3123 
3124  std::vector<DataType> cellStateSupportedTypes =
3125  {
3127  };
3128 
3129  std::vector<DataType> weightsSupportedTypes =
3130  {
3132  };
3133 
3134  std::vector<DataType> layerNormPeepholeWeightsSupportedTypes =
3135  {
3137  };
3138 
3139  std::vector<DataType> biasSupportedTypes =
3140  {
3142  };
3143 
3144  // Validate types of input/output tensors
3145  ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3146  ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3147  ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3148 
3149  ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3150  ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3151  ValidateDataTypes(outputInfo, inputOutputSupportedTypes, descriptorName);
3152 
3153  // Validate matching types of input/output tensors
3154  ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3155  ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3156  "outputStateIn", "outputStateOut");
3157  ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3158 
3159  // Infer number of batches, number of units, input size and output size from tensor dimensions
3160  const uint32_t numBatches = inputInfo.GetShape()[0];
3161  const uint32_t inputSize = inputInfo.GetShape()[1];
3162  const uint32_t outputSize = outputStateInInfo.GetShape()[1];
3163  const uint32_t numUnits = cellStateInInfo.GetShape()[1];
3164 
3165  // Validate number of dimensions and number of elements for input/output tensors
3166  ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3167  ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3168  ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * numUnits), descriptorName + " cellStateIn");
3169 
3170  ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3171  ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * numUnits), descriptorName + " cellStateOut");
3172  ValidateTensorNumDimNumElem(outputInfo, 2, (numBatches * outputSize), descriptorName + " output");
3173 
3174  // Validate number of dimensions and number of elements for MANDATORY weight tensors
3175  ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3176  auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3177  ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (numUnits * inputSize), " InputToForgetWeights");
3178 
3179  ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3180  auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3181  ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (numUnits * inputSize), " InputToCellWeights");
3182 
3183  ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3184  auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3185  ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (numUnits * inputSize), " InputToOutputWeights");
3186 
3187  ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3188  auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3189  ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (numUnits * outputSize),
3190  " RecurrentToForgetWeights");
3191 
3192  ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3193  auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3194  ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3195 
3196  ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3197  auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3198  ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3199 
3200  // Validate data types for MANDATORY weights tensors (all should match each other)
3201  ValidateDataTypes(inputToForgetWeightsInfo, weightsSupportedTypes, descriptorName);
3202 
3203  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToCellWeightsInfo, descriptorName,
3204  "inputToForgetWeights", "inputToCellWeights");
3205  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3206  "inputToForgetWeights", "inputToOutputWeights");
3207 
3208  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3209  "inputToForgetWeights", "recurrentToForgeteights");
3210  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3211  "inputToForgetWeights", "recurrentToCellWeights");
3212  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3213  "inputToForgetWeights", "recurrentToOutputWeights");
3214 
3215  // Validate number of dimensions and number of elements for MANDATORY bias tensors
3216  ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3217  auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3218  ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, numUnits, " ForgetGateBias");
3219 
3220  ValidatePointer(m_CellBias, descriptorName, "CellBias");
3221  auto cellBiasInfo = m_CellBias->GetTensorInfo();
3222  ValidateTensorNumDimNumElem(cellBiasInfo, 1, numUnits, " CellBias");
3223 
3224  ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3225  auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3226  ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, numUnits, " OutputGateBias");
3227 
3228  // Validate data types for MANDATORY bias tensors
3229  ValidateDataTypes(forgetGateBiasInfo, biasSupportedTypes, descriptorName);
3230 
3231  ValidateTensorDataTypesMatch(forgetGateBiasInfo, cellBiasInfo, descriptorName,
3232  "forgetGateBias", "cellBias");
3233  ValidateTensorDataTypesMatch(forgetGateBiasInfo, outputGateBiasInfo, descriptorName,
3234  "forgetGateBias", "outputGateBias");
3235 
3236  // Validate OPTIONAL params: CIFG (inputToInputWeights, recurrentToInputWeights, inputGateBias)
3237  const bool allCifgParamsPresentOrNot = ((m_InputToInputWeights && m_RecurrentToInputWeights && m_InputGateBias &&
3238  !m_Parameters.m_CifgEnabled) ||
3239  (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
3240  !m_InputGateBias && m_Parameters.m_CifgEnabled));
3241 
3242  if (!allCifgParamsPresentOrNot)
3243  {
3244  throw InvalidArgumentException(descriptorName +
3245  ": InputToInputWeights, RecurrentToInputWeights and InputGateBias must either all be present "
3246  "(CIFG disabled) or not be present at all (CIFG enabled). m_Parameters.m_CifgEnabled should be "
3247  "set appropriately.");
3248  }
3249 
3250  if (!m_Parameters.m_CifgEnabled)
3251  {
3252  // Validate number of dimensions and number of elements
3253  auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3254  ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (numUnits * inputSize), " InputToInputWeights");
3255 
3256  auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3257  ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (numUnits * outputSize),
3258  " RecurrentToInputWeights");
3259 
3260  auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3261  ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, numUnits, " InputGateBias");
3262 
3263  // Validate data types
3264  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToInputWeightsInfo, descriptorName,
3265  "inputToForgetWeights", "inputToInputWeights");
3266  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3267  "inputToForgetWeights", "recurrentToInputWeights");
3268  ValidateTensorDataTypesMatch(forgetGateBiasInfo, inputGateBiasInfo, descriptorName,
3269  "forgetGateBias", "inputGateBias");
3270  }
3271 
3272  // Validate OPTIONAL params: Peephole (cellToInputWeights, cellToForgetWeights, cellToOutputWeights)
3273  bool allPeepholeWeightsPresentOrNot =
3274  (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
3275  && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
3276  || (!m_CellToInputWeights && !m_CellToForgetWeights
3277  && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
3278 
3279  if (!allPeepholeWeightsPresentOrNot)
3280  {
3281  throw InvalidArgumentException(descriptorName +
3282  ": CellToInputWeights, CellToForgetWeights and CellToOutputWeights should all be present (Peephole "
3283  "enabled) or not be present at all (Peephole disabled). CellToInputWeights should only be present "
3284  "when Peephole is enabled and CIFG is disabled. m_Parameters.m_PeepholeEnabled should be set "
3285  "appropriately.");
3286  }
3287 
3288  if (m_Parameters.m_PeepholeEnabled)
3289  {
3290  auto cellToForgetWeightsInfo = m_CellToForgetWeights->GetTensorInfo();
3291  ValidateTensorNumDimNumElem(cellToForgetWeightsInfo, 1, numUnits, " cellToForgetWeights");
3292  ValidateDataTypes(cellToForgetWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3293 
3294  auto cellToOutputWeightsInfo = m_CellToOutputWeights->GetTensorInfo();
3295  ValidateTensorNumDimNumElem(cellToOutputWeightsInfo, 1, numUnits, " cellToOutputWeights");
3296  ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToOutputWeightsInfo, descriptorName,
3297  "cellToForgetWeight", "cellToOutputWeights");
3298 
3299  if (!m_Parameters.m_CifgEnabled)
3300  {
3301  auto cellToInputWeightsInfo = m_CellToInputWeights->GetTensorInfo();
3302  ValidateTensorNumDimNumElem(cellToInputWeightsInfo, 1, numUnits, " cellToInputWeights");
3303  ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToInputWeightsInfo, descriptorName,
3304  "cellToForgetWeights", "cellToInputWeights");
3305  }
3306  }
3307 
3308  // Validate OPTIONAL params: Layer Norm Weights
3309  bool allLayerNormWeightsPresentOrNot =
3310  (((m_InputLayerNormWeights || m_Parameters.m_CifgEnabled) && m_ForgetLayerNormWeights
3311  && m_CellLayerNormWeights && m_OutputLayerNormWeights && m_Parameters.m_LayerNormEnabled)
3312  || (!m_InputLayerNormWeights && !m_ForgetLayerNormWeights && !m_CellLayerNormWeights
3313  && !m_OutputLayerNormWeights && !m_Parameters.m_LayerNormEnabled));
3314 
3315  if (!allLayerNormWeightsPresentOrNot)
3316  {
3317  throw InvalidArgumentException(descriptorName +
3318  ": InputLayerNormWeights, ForgetLayerNormWeights, m_OutputLayerNormWeights "
3319  "and CellLayerNormWeights should all be present (Layer Norm enabled) or not "
3320  "be present at all (Layer Norm disabled). InputLayerNormWeights should "
3321  "only be present when Layer Norm is enabled and CIFG is disabled. "
3322  "m_Parameters.m_LayerNormEnabled should be set appropriately.");
3323  }
3324 
3325  if (m_Parameters.m_LayerNormEnabled)
3326  {
3327  auto forgetLayerNormWeightsInfo = m_ForgetLayerNormWeights->GetTensorInfo();
3328  ValidateTensorNumDimNumElem(forgetLayerNormWeightsInfo, 1, numUnits, " forgetLayerNormWeights");
3329  ValidateDataTypes(forgetLayerNormWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3330 
3331  auto cellLayerNormWeightsInfo = m_CellLayerNormWeights->GetTensorInfo();
3332  ValidateTensorNumDimNumElem(cellLayerNormWeightsInfo, 1, numUnits, " cellLayerNormWeights");
3333  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, cellLayerNormWeightsInfo, descriptorName,
3334  "forgetLayerNormWeights", "cellLayerNormWeights");
3335 
3336  auto outputLayerNormWeightsInfo = m_OutputLayerNormWeights->GetTensorInfo();
3337  ValidateTensorNumDimNumElem(outputLayerNormWeightsInfo, 1, numUnits, " outputLayerNormWeights");
3338  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, outputLayerNormWeightsInfo, descriptorName,
3339  "forgetLayerNormWeights", "outputLayerNormWeights");
3340 
3341  if (!m_Parameters.m_CifgEnabled)
3342  {
3343  auto inputLayerNormWeightsInfo = m_InputLayerNormWeights->GetTensorInfo();
3344  ValidateTensorNumDimNumElem(inputLayerNormWeightsInfo, 1, numUnits, " inputLayerNormWeights");
3345  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, inputLayerNormWeightsInfo, descriptorName,
3346  "forgetLayerNormWeights", "inputLayerNormWeights");
3347  }
3348  }
3349 
3350  // Validate OPTIONAL params: Projection (projectionWeights, projectionBias)
3351  bool correctProjectionTensorsPresent =
3352  ((!m_ProjectionWeights && !m_ProjectionBias && !m_Parameters.m_ProjectionEnabled) ||
3353  (m_ProjectionWeights && !m_ProjectionBias && m_Parameters.m_ProjectionEnabled) ||
3354  (m_ProjectionWeights && m_ProjectionBias && m_Parameters.m_ProjectionEnabled));
3355 
3356  if (!correctProjectionTensorsPresent)
3357  {
3358  throw InvalidArgumentException(descriptorName +
3359  ": If projection is enabled, ProjectionWeights should be present and "
3360  "ProjectionBias is optional. If projection is disabled, neither "
3361  "ProjectionWeights nor ProjectionBias should be present.");
3362  }
3363 
3364  if (m_Parameters.m_ProjectionEnabled)
3365  {
3366  auto projectionWeightsInfo = m_ProjectionWeights->GetTensorInfo();
3367  ValidateTensorNumDimNumElem(projectionWeightsInfo, 2, (numUnits * outputSize), "ProjectionWeights");
3368  ValidateDataTypes(projectionWeightsInfo, weightsSupportedTypes, descriptorName);
3369 
3370  if (m_ProjectionBias)
3371  {
3372  auto projectionBiasInfo = m_ProjectionBias->GetTensorInfo();
3373  ValidateTensorNumDimNumElem(projectionBiasInfo, 1, outputSize, "ProjectionBias");
3374  ValidateDataTypes(projectionBiasInfo, biasSupportedTypes, descriptorName);
3375  }
3376 
3377  }
3378  else if ((outputInfo.GetQuantizationScale() != m_Parameters.m_HiddenStateScale) &&
3379  outputInfo.GetQuantizationOffset() != m_Parameters.m_HiddenStateZeroPoint) {
3380  throw InvalidArgumentException(descriptorName +
3381  ": If projection is disabled, output quantization info (scale, offset) "
3382  "should match HiddenStateScale and HiddenStateZeroPoint.");
3383  }
3384 
3385 }
3386 
3388 {
3389  const std::string descriptorName{"QuantizedLstmQueueDescriptor"};
3390 
3391  // Validate number of inputs/outputs
3392  ValidateNumInputs(workloadInfo, descriptorName, 3);
3393  ValidateNumOutputs(workloadInfo, descriptorName, 2);
3394 
3395  // Input/output tensor infos
3396  auto inputInfo = workloadInfo.m_InputTensorInfos[0];
3397  auto cellStateInInfo = workloadInfo.m_InputTensorInfos[1];
3398  auto outputStateInInfo = workloadInfo.m_InputTensorInfos[2];
3399 
3400  auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
3401  auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
3402 
3403  std::vector<DataType> inputOutputSupportedTypes =
3404  {
3406  };
3407 
3408  std::vector<DataType> cellStateSupportedTypes =
3409  {
3411  };
3412 
3413  std::vector<DataType> weightsSupportedTypes =
3414  {
3416  };
3417 
3418  std::vector<DataType> biasSupportedTypes =
3419  {
3421  };
3422 
3423  // Validate types of input/output tensors
3424  ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3425  ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3426  ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3427 
3428  ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3429  ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3430 
3431  // Validate matching types of input/output tensors
3432  ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3433  ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3434  "outputStateIn", "outputStateOut");
3435  ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3436 
3437  // Validate matching quantization info for input/output tensors
3438  ValidateTensorQuantizationSpace(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3439  ValidateTensorQuantizationSpace(inputInfo, outputStateOutInfo, descriptorName, "input", "outputStateOut");
3440  ValidateTensorQuantizationSpace(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3441 
3442  // Infer number of batches, input size and output size from tensor dimensions
3443  const uint32_t numBatches = inputInfo.GetShape()[0];
3444  const uint32_t inputSize = inputInfo.GetShape()[1];
3445  const uint32_t outputSize = cellStateInInfo.GetShape()[1];
3446 
3447  // Validate number of dimensions and number of elements for input/output tensors
3448  ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3449  ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * outputSize), descriptorName + " cellStateIn");
3450  ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3451  ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * outputSize), descriptorName + " cellStateOut");
3452  ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3453 
3454  // Validate number of dimensions and number of elements for weights tensors
3455  ValidatePointer(m_InputToInputWeights, descriptorName, "InputToInputWeights");
3456  auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3457  ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (outputSize * inputSize), " InputToInputWeights");
3458 
3459  ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3460  auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3461  ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (outputSize * inputSize), " InputToForgetWeights");
3462 
3463  ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3464  auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3465  ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (outputSize * inputSize), " InputToCellWeights");
3466 
3467  ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3468  auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3469  ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (outputSize * inputSize), " InputToOutputWeights");
3470 
3471  ValidatePointer(m_RecurrentToInputWeights, descriptorName, "RecurrentToInputWeights");
3472  auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3473  ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToInputWeights");
3474 
3475  ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3476  auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3477  ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (outputSize * outputSize),
3478  " RecurrentToForgetWeights");
3479 
3480  ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3481  auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3482  ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3483 
3484  ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3485  auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3486  ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3487 
3488  // Validate data types for weights tensors (all should match each other)
3489  ValidateDataTypes(inputToInputWeightsInfo, weightsSupportedTypes, descriptorName);
3490 
3491  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToForgetWeightsInfo, descriptorName,
3492  "inputToInputWeights", "inputToForgetWeights");
3493  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToCellWeightsInfo, descriptorName,
3494  "inputToInputWeights", "inputToCellWeights");
3495  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3496  "inputToInputWeights", "inputToOutputWeights");
3497 
3498  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3499  "inputToInputWeights", "recurrentToInputWeights");
3500  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3501  "inputToInputWeights", "recurrentToForgeteights");
3502  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3503  "inputToInputWeights", "recurrentToCellWeights");
3504  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3505  "inputToInputWeights", "recurrentToOutputWeights");
3506 
3507  // Validate matching quantization info for weight tensors (all should match each other)
3508  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToForgetWeightsInfo,
3509  descriptorName, "inputToInputWeights", "inputToForgetWeights");
3510  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToCellWeightsInfo,
3511  descriptorName, "inputToInputWeights", "inputToCellWeights");
3512  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToOutputWeightsInfo,
3513  descriptorName, "inputToInputWeights", "inputToOutputWeights");
3514 
3515  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToInputWeightsInfo,
3516  descriptorName, "inputToInputWeights", "recurrentToInputWeights");
3517  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToForgetWeightsInfo,
3518  descriptorName, "inputToInputWeights", "recurrentToForgetWeights");
3519  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToCellWeightsInfo,
3520  descriptorName, "inputToInputWeights", "recurrentToCellWeights");
3521  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToOutputWeightsInfo,
3522  descriptorName, "inputToInputWeights", "recurrentToOutputWeights");
3523 
3524  // Validate number of dimensions and number of elements in bias tensors
3525  ValidatePointer(m_InputGateBias, descriptorName, "InputGateBias");
3526  auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3527  ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, outputSize, " InputGateBias");
3528 
3529  ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3530  auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3531  ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, outputSize, " ForgetGateBias");
3532 
3533  ValidatePointer(m_CellBias, descriptorName, "CellBias");
3534  auto cellBiasInfo = m_CellBias->GetTensorInfo();
3535  ValidateTensorNumDimNumElem(cellBiasInfo, 1, outputSize, " CellBias");
3536 
3537  ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3538  auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3539  ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, outputSize, " OutputGateBias");
3540 
3541  // Validate data types for bias tensors (all should match each other)
3542  ValidateDataTypes(inputGateBiasInfo, biasSupportedTypes, descriptorName);
3543 
3544  ValidateTensorDataTypesMatch(inputGateBiasInfo, forgetGateBiasInfo, descriptorName,
3545  "inputGateBias", "forgetGateBias");
3546  ValidateTensorDataTypesMatch(inputGateBiasInfo, cellBiasInfo, descriptorName,
3547  "inputGateBias", "cellBias");
3548  ValidateTensorDataTypesMatch(inputGateBiasInfo, outputGateBiasInfo, descriptorName,
3549  "inputGateBias", "outputGateBias");
3550 
3551  // Validate bias tensor quantization info
3552  ValidateBiasTensorQuantization(inputGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3553  ValidateBiasTensorQuantization(forgetGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3554  ValidateBiasTensorQuantization(cellBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3555  ValidateBiasTensorQuantization(outputGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3556 }
3557 
3558 void AbsQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3559 {
3560  const std::string descriptorName{"AbsQueueDescriptor"};
3561 
3562  ValidateNumInputs(workloadInfo, descriptorName, 1);
3563  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3564 
3565  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3566  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3567 
3568  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3569 
3570  std::vector<DataType> supportedTypes =
3571  {
3579  };
3580 
3581  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3582  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3583 }
3584 
3585 void SliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3586 {
3587  const std::string descriptorName{"SliceQueueDescriptor"};
3588 
3589  ValidateNumInputs(workloadInfo, descriptorName, 1);
3590  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3591 
3592  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3593  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3594 
3595  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3596 
3597  const unsigned int rank = inputTensorInfo.GetNumDimensions();
3598  if (rank > 4)
3599  {
3600  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
3601  }
3602 
3603  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, rank, "output");
3604 
3605  // Check if m_Begin and m_Size have the expected length
3606  if (m_Parameters.m_Begin.size() != rank)
3607  {
3608  throw InvalidArgumentException(descriptorName +
3609  ": Length of begin offset descriptor must equal rank " + std::to_string(rank));
3610  }
3611  if (m_Parameters.m_Size.size() != rank)
3612  {
3613  throw InvalidArgumentException(descriptorName +
3614  ": Length of size descriptor must equal rank " + std::to_string(rank));
3615  }
3616 
3617  // Check if the shape of the output tensor matches m_Size
3618  const TensorShape& outputShape = outputTensorInfo.GetShape();
3619  for (unsigned int i = 0u; i < rank; ++i)
3620  {
3621  if (m_Parameters.m_Size[i] != outputShape[i])
3622  {
3623  throw InvalidArgumentException(descriptorName + ": Size descriptor does not match output tensor.");
3624  }
3625  }
3626 
3627  // Check if the sum of begin offset and size in a given dimension
3628  // does not exceed the size of corresponding input
3629  const TensorShape& inputShape = inputTensorInfo.GetShape();
3630  for(unsigned int i = 0u; i < rank; ++i)
3631  {
3632  if (m_Parameters.m_Begin[i] + m_Parameters.m_Size[i] > inputShape[i])
3633  {
3634  throw InvalidArgumentException(descriptorName + ": Sum of begin offset and size for dimension " +
3635  std::to_string(i) + " exceeds input size.");
3636  }
3637  }
3638 }
3639 
3641 {
3642  const std::string descriptorName{"DepthToSpaceQueueDescriptor"};
3643 
3644  ValidateNumInputs(workloadInfo, descriptorName, 1);
3645  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3646 
3647  const TensorInfo& inputInfo = workloadInfo.m_InputTensorInfos[0];
3648  const TensorInfo& outputInfo = workloadInfo.m_OutputTensorInfos[0];
3649 
3650  ValidateTensorNumDimensions(inputInfo, descriptorName, 4, "input");
3651  ValidateTensorNumDimensions(outputInfo, descriptorName, 4, "output");
3652 
3653  std::vector<DataType> supportedTypes =
3654  {
3661  };
3662 
3663  ValidateDataTypes(inputInfo, supportedTypes, descriptorName);
3664  ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
3665 
3666  ValidateTensorNumElementsMatch(inputInfo, outputInfo, descriptorName, "input", "output");
3667 
3668  if (m_Parameters.m_BlockSize == 0)
3669  {
3670  throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
3671  }
3672 
3673  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
3674  const unsigned int wIndex = dimensionIndices.GetWidthIndex();
3675  const unsigned int hIndex = dimensionIndices.GetHeightIndex();
3676  const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
3677 
3678  const TensorShape& outputShape = outputInfo.GetShape();
3679  if (outputShape[hIndex] % m_Parameters.m_BlockSize != 0 || outputShape[wIndex] % m_Parameters.m_BlockSize != 0)
3680  {
3681  throw InvalidArgumentException(descriptorName + ": Output width and height shape"
3682  "must be divisible by block size.");
3683  }
3684 
3685  const TensorShape& inputShape = inputInfo.GetShape();
3686  if (inputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
3687  {
3688  throw InvalidArgumentException(descriptorName + ": The depth of the input tensor"
3689  "must be divisible by the square of block size." );
3690  }
3691 }
3692 
3693 void ComparisonQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3694 {
3695  const std::string descriptorName{"ComparisonQueueDescriptor"};
3696 
3697  ValidateNumInputs(workloadInfo, descriptorName, 2);
3698  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3699 
3700  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3701  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3702  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3703 
3704  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3705  inputTensorInfo1,
3706  outputTensorInfo,
3707  descriptorName,
3708  "input_0",
3709  "input_1");
3710 
3711  if (outputTensorInfo.GetDataType() != DataType::Boolean)
3712  {
3713  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3714  }
3715 }
3716 
3718 {
3719  const std::string descriptorName{"ElementwiseUnaryQueueDescriptor"};
3720 
3721  ValidateNumInputs(workloadInfo, descriptorName, 1);
3722  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3723 
3724  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3725  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3726 
3727  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3728 
3729  std::vector<DataType> supportedTypes =
3730  {
3738  };
3739 
3740  std::vector<DataType> logicalSupportedTypes =
3741  {
3743  };
3744 
3745  if (m_Parameters.m_Operation == UnaryOperation::LogicalNot)
3746  {
3747  ValidateDataTypes(inputTensorInfo, logicalSupportedTypes, descriptorName);
3748  }
3749  else
3750  {
3751  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3752  }
3753 
3754 
3755  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3756 }
3757 
3758 void RankQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3759 {
3760  const std::string descriptorName{"RankQueueDescriptor"};
3761 
3762  ValidateNumInputs(workloadInfo, descriptorName, 1);
3763  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3764 
3765  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3766  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3767 
3768  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
3769  ValidateTensorNumElements(outputTensorInfo, descriptorName, 1, "output");
3770 
3771  std::vector<DataType> supportedTypes =
3772  {
3781  };
3782 
3783  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3784  ValidateDataTypes(outputTensorInfo, { DataType::Signed32 }, descriptorName);
3785 }
3786 
3788 {
3789  const std::string descriptorName{"LogicalBinaryQueueDescriptor"};
3790 
3791  ValidateNumInputs(workloadInfo, descriptorName, 2);
3792  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3793 
3794  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3795  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3796  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3797 
3798  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3799  inputTensorInfo1,
3800  outputTensorInfo,
3801  descriptorName,
3802  "input_0",
3803  "input_1");
3804 
3805  if (inputTensorInfo0.GetDataType() != DataType::Boolean)
3806  {
3807  throw InvalidArgumentException(descriptorName + ": Input tensor 0 type must be Boolean.");
3808  }
3809 
3810  if (inputTensorInfo1.GetDataType() != DataType::Boolean)
3811  {
3812  throw InvalidArgumentException(descriptorName + ": Input tensor 1 type must be Boolean.");
3813  }
3814 
3815  if (outputTensorInfo.GetDataType() != DataType::Boolean)
3816  {
3817  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3818  }
3819 }
3820 
3821 void ReduceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3822 {
3823  const std::string descriptorName{"ReduceQueueDescriptor"};
3824 
3825  ValidateNumInputs(workloadInfo, descriptorName, 1);
3826  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3827 
3828  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3829  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3830 
3831  std::vector<DataType> supportedTypes =
3832  {
3840  };
3841 
3842  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3843  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3844 }
3845 
3847 {
3848  // Modified from LstmQueueDescriptor::Validate to support UnidirectionalSequenceLstm
3849 
3850  const std::string descriptorName{"UnidirectionalSequenceLstmQueueDescriptor"};
3851 
3852  // check dimensions of all inputs and outputs
3853  if (workloadInfo.m_InputTensorInfos.size() != 3)
3854  {
3855  throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
3856  }
3857  if (workloadInfo.m_OutputTensorInfos.size() != 3)
3858  {
3859  throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
3860  }
3861 
3862  std::vector<DataType> supportedTypes =
3863  {
3866  };
3867 
3868  // check for supported type of one input and match them with all the other input and output
3869  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
3870 
3871  // Making sure clipping parameters have valid values.
3872  // == 0 means no clipping
3873  // > 0 means clipping
3874  if (m_Parameters.m_ClippingThresCell < 0.0f)
3875  {
3876  throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
3877  }
3878  if (m_Parameters.m_ClippingThresProj < 0.0f)
3879  {
3880  throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
3881  }
3882 
3883  unsigned int batchIndx = 0;
3884  unsigned int inputIndx = 1;
3885  uint32_t timeStep = 1;
3886  unsigned int timeIndx = 1;
3887  inputIndx = 2;
3888  if (m_Parameters.m_TimeMajor)
3889  {
3890  batchIndx = 1;
3891  timeIndx = 0;
3892 
3893  }
3894  timeStep = workloadInfo.m_InputTensorInfos[0].GetShape()[timeIndx];
3895 
3896  // Inferring batch size, number of outputs and number of cells from the inputs.
3897  const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[inputIndx];
3898  const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[batchIndx];
3899  ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
3900  const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
3901  ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
3902  const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
3903 
3904  // input tensor
3905  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 3, (timeStep * n_batch * n_input),
3906  descriptorName + " input_0");
3907  // outputStateInTensor
3908  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
3909  descriptorName + " input_1");
3910  // outputStateInTensor
3911  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
3912  descriptorName + " input_2");
3913 
3914  // outputTensor
3915  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 3, (timeStep * n_batch * n_output),
3916  descriptorName + " output_0");
3917 
3918  // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
3919  if ( m_InputToInputWeights )
3920  {
3921  ValidateTensorNumDimNumElem(m_InputToInputWeights->GetTensorInfo(), 2,
3922  (n_cell * n_input), "InputLayerNormWeights");
3923  }
3924 
3925  ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
3926  ValidateTensorNumDimNumElem(m_InputToForgetWeights->GetTensorInfo(), 2,
3927  (n_cell * n_input), "InputToForgetWeights");
3928 
3929  ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
3930  ValidateTensorNumDimNumElem(m_InputToCellWeights->GetTensorInfo(), 2,
3931  (n_cell * n_input), "InputToCellWeights");
3932 
3933  if ( m_RecurrentToInputWeights )
3934  {
3935  ValidateTensorNumDimNumElem(m_RecurrentToInputWeights->GetTensorInfo(), 2,
3936  (n_cell * n_output), "RecurrentToInputWeights");
3937  }
3938 
3939  ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
3940  ValidateTensorNumDimNumElem(m_RecurrentToForgetWeights->GetTensorInfo(), 2,
3941  (n_cell * n_output), "RecurrentToForgetWeights");
3942 
3943  ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
3944  ValidateTensorNumDimNumElem(m_RecurrentToCellWeights->GetTensorInfo(), 2,
3945  (n_cell * n_output), "RecurrentToCellWeights");
3946 
3947  // Make sure the input-gate's parameters are either both present (regular
3948  // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
3949  bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
3950  !m_Parameters.m_CifgEnabled) ||
3951  (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
3952  m_Parameters.m_CifgEnabled));
3953  if (!cifg_weights_all_or_none)
3954  {
3955  throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
3956  "RecurrentToInputWeights must either both be present (regular LSTM) "
3957  "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
3958  "accordingly.");
3959  }
3960 
3961  if ( m_CellToInputWeights )
3962  {
3963  ValidateTensorNumDimNumElem(m_CellToInputWeights->GetTensorInfo(), 1,
3964  n_cell, "CellToInputWeights");
3965  }
3966  if ( m_CellToForgetWeights )
3967  {
3968  ValidateTensorNumDimNumElem(m_CellToForgetWeights->GetTensorInfo(), 1,
3969  n_cell, "CellToForgetWeights");
3970  }
3971  if ( m_CellToOutputWeights )
3972  {
3973  ValidateTensorNumDimNumElem(m_CellToOutputWeights->GetTensorInfo(), 1,
3974  n_cell, "CellToOutputWeights");
3975  }
3976 
3977  // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
3978  bool peephole_weights_all_or_none =
3979  (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
3980  && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
3981  || ( !m_CellToInputWeights && !m_CellToForgetWeights
3982  && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
3983  if (!peephole_weights_all_or_none)
3984  {
3985  throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
3986  }
3987 
3988  // Make sure the input gate bias is present only when not a CIFG-LSTM.
3989  if (m_Parameters.m_CifgEnabled)
3990  {
3991  if (m_InputGateBias)
3992  {
3993  throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
3994  }
3995  }
3996  else
3997  {
3998  if (!m_InputGateBias)
3999  {
4000  throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
4001  "must be present.");
4002  }
4003  ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1,
4004  n_cell, "InputGateBias");
4005  }
4006 
4007  ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
4008  ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
4009 
4010  ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
4011  ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
4012 
4013  ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
4014  ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
4015 
4016  if (m_ProjectionWeights)
4017  {
4018  ValidateTensorNumDimNumElem(m_ProjectionWeights->GetTensorInfo(), 2,
4019  (n_cell * n_output), "ProjectionWeights");
4020  }
4021  if (m_ProjectionBias)
4022  {
4023  ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
4024  }
4025 
4026  // Making sure the projection tensors are consistent:
4027  // 1) If projection weight is not present, then projection bias should not be
4028  // present.
4029  // 2) If projection weight is present, then projection bias is optional.
4030  bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
4031  !m_Parameters.m_ProjectionEnabled)
4032  || (m_ProjectionWeights && !m_ProjectionBias &&
4033  m_Parameters.m_ProjectionEnabled)
4034  || (m_ProjectionWeights && m_ProjectionBias &&
4035  m_Parameters.m_ProjectionEnabled));
4036  if (!projecton_tensors_consistent)
4037  {
4038  throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
4039  }
4040 
4041  // The four layer normalization weights either all have values or none of them have values. Additionally, if
4042  // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
4043  // either all have values or none of them have values. Layer normalization is used when the values of all the
4044  // layer normalization weights are present
4045  if (m_InputLayerNormWeights)
4046  {
4047  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
4048  }
4049  if (m_ForgetLayerNormWeights)
4050  {
4051  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
4052  }
4053  if (m_CellLayerNormWeights)
4054  {
4055  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
4056  }
4057  if (m_OutputLayerNormWeights)
4058  {
4059  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
4060  }
4061 
4062  if (m_Parameters.m_LayerNormEnabled)
4063  {
4064  if (!m_Parameters.m_CifgEnabled)
4065  {
4066  if (!m_InputLayerNormWeights)
4067  {
4068  throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
4069  "disabled but InputLayerNormWeights are not present");
4070  }
4071  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(),
4072  1, n_cell, "InputLayerNormWeights");
4073  }
4074  else if (m_InputLayerNormWeights)
4075  {
4076  throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
4077  "enabled");
4078  }
4079 
4080  ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
4081  "ForgetLayerNormWeights");
4082  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
4083 
4084  ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
4085  "OutputLayerNormWeights");
4086  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
4087 
4088  ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
4089  "CellLayerNormWeights");
4090  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
4091  }
4092  else if (m_InputLayerNormWeights || m_ForgetLayerNormWeights || m_OutputLayerNormWeights || m_CellLayerNormWeights)
4093  {
4094  throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
4095  "normalisation weights are present.");
4096  }
4097 }
4098 
4100 {
4101  const std::string descriptorName{"BatchMatMulDescriptor"};
4102 
4103  ValidateNumInputs(workloadInfo, descriptorName, 2);
4104  ValidateNumOutputs(workloadInfo, descriptorName, 1);
4105 
4106  // Inputs must be: both 2D+
4107  // For inputs X and Y whose dimensions to be multiplied are (M,N) and (I,J) respectively,
4108  // axes N and I must be the same size
4109 
4110  const auto& inputXInfoBeforeParams = workloadInfo.m_InputTensorInfos[0];
4111  const auto& inputYInfoBeforeParams = workloadInfo.m_InputTensorInfos[1];
4112  const auto& outputInfo = workloadInfo.m_OutputTensorInfos[0];
4113  // Output info has already been inferred
4114 
4115  std::vector<DataType> supportedTypes =
4116  {
4123  };
4124 
4125  ValidateDataTypes(inputXInfoBeforeParams, supportedTypes, descriptorName);
4126  ValidateDataTypes(inputYInfoBeforeParams, supportedTypes, descriptorName);
4127  ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
4128 
4129  if ((inputXInfoBeforeParams.GetNumDimensions() < 2) ||
4130  (inputYInfoBeforeParams.GetNumDimensions() < 2))
4131  {
4132  throw InvalidArgumentException(descriptorName + ": Input tensors are not 2D or greater.");
4133  }
4134 
4135  TensorInfo inputXInfoAfterParams;
4136  TensorInfo inputYInfoAfterParams;
4137 
4138  if((m_Parameters.m_TransposeX && m_Parameters.m_AdjointX) ||
4139  (m_Parameters.m_TransposeY && m_Parameters.m_AdjointY))
4140  {
4141  throw InvalidArgumentException(descriptorName +
4142  ": Invalid descriptor parameters - Transpose and Adjoint "
4143  "cannot both be true for a given input tensor.");
4144  }
4145  if(m_Parameters.m_TransposeX)
4146  {
4147  inputXInfoAfterParams = armnnUtils::Permuted(inputXInfoBeforeParams,
4149  m_Parameters.m_DataLayoutX,
4150  inputXInfoBeforeParams.GetShape()));
4151  }
4152  else if(m_Parameters.m_AdjointX)
4153  {
4154  auto axesToMul = BatchMatMulDescriptor::GetAxesToMul(m_Parameters.m_DataLayoutX,
4155  inputXInfoBeforeParams.GetShape());
4156  if(inputXInfoBeforeParams.GetShape()[axesToMul.first] !=
4157  inputXInfoBeforeParams.GetShape()[axesToMul.second])
4158  {
4159  throw InvalidArgumentException(descriptorName +
4160  ": Adjoint is set to true for input tensor X, but the axes to be adjointed are not square." );
4161  }
4162  // Shape remains the same as it's square
4163  inputXInfoAfterParams = inputXInfoBeforeParams;
4164  }
4165  else
4166  {
4167  inputXInfoAfterParams = inputXInfoBeforeParams;
4168  }
4169 
4170  if(m_Parameters.m_TransposeY)
4171  {
4172  inputYInfoAfterParams = armnnUtils::Permuted(inputYInfoBeforeParams,
4174  m_Parameters.m_DataLayoutY,
4175  inputYInfoBeforeParams.GetShape()));
4176  }
4177  else if(m_Parameters.m_AdjointY)
4178  {
4179  auto axesToMul = BatchMatMulDescriptor::GetAxesToMul(m_Parameters.m_DataLayoutY,
4180  inputYInfoBeforeParams.GetShape());
4181  if(inputYInfoBeforeParams.GetShape()[axesToMul.first] !=
4182  inputYInfoBeforeParams.GetShape()[axesToMul.second])
4183  {
4184  throw InvalidArgumentException(descriptorName +
4185  ": Adjoint is set to true for input tensor Y, but the axes to be adjointed are not square." );
4186  }
4187  // Shape remains the same as it's square
4188  inputYInfoAfterParams = inputYInfoBeforeParams;
4189  }
4190  else
4191  {
4192  inputYInfoAfterParams = inputYInfoBeforeParams;
4193  }
4194 
4195  switch(m_Parameters.m_DataLayoutX)
4196  {
4197  case DataLayout::NCDHW:
4198  case DataLayout::NDHWC:
4199  if(inputXInfoAfterParams.GetNumDimensions() < 3)
4200  {
4201  throw InvalidArgumentException(descriptorName +
4202  ": Input tensor X does not have the correct "
4203  "number of dimensions for the Data Layout that it has been assigned.");
4204  }
4205  break;
4206  case DataLayout::NCHW:
4207  case DataLayout::NHWC:
4208  default:
4209  break;
4210  }
4211 
4212  switch(m_Parameters.m_DataLayoutY)
4213  {
4214  case DataLayout::NCDHW:
4215  case DataLayout::NDHWC:
4216  if(inputYInfoAfterParams.GetNumDimensions() < 3)
4217  {
4218  throw InvalidArgumentException(descriptorName +
4219  ": Input tensor Y does not have the correct "
4220  "number of dimensions for the Data Layout that it has been assigned.");
4221  }
4222  break;
4223  case DataLayout::NCHW:
4224  case DataLayout::NHWC:
4225  default:
4226  break;
4227  }
4228 
4229  auto axesXToMul = BatchMatMulDescriptor::GetAxesToMul(m_Parameters.m_DataLayoutX,
4230  inputXInfoAfterParams.GetShape());
4231  auto axesYToMul = BatchMatMulDescriptor::GetAxesToMul(m_Parameters.m_DataLayoutY,
4232  inputXInfoBeforeParams.GetShape());
4233 
4234  if(inputXInfoAfterParams.GetShape()[axesXToMul.second]
4235  != inputYInfoAfterParams.GetShape()[axesYToMul.first])
4236  {
4237  throw InvalidArgumentException(descriptorName +
4238  ": The final axis of input tensor X must be the same size as "
4239  "the second last axis of input tensor Y.");
4240  }
4241 
4242  { // Separate scope so we don't pollute the rest of the scope with our temp variables
4243  // e.g. NHWC isnt compatible with NCHW as of now
4244  DataLayout xLayout = m_Parameters.m_DataLayoutX;
4245  DataLayout yLayout = m_Parameters.m_DataLayoutY;
4246 
4247  if(xLayout == DataLayout::NCHW || xLayout == DataLayout::NCDHW)
4248  {
4249  if(yLayout == DataLayout::NHWC || yLayout == DataLayout::NDHWC)
4250  {
4251  throw InvalidArgumentException(descriptorName +
4252  ": Invalid input tensor data layout combination.");
4253  }
4254  }
4255  if(yLayout == DataLayout::NCHW || yLayout == DataLayout::NCDHW)
4256  {
4257  if(xLayout == DataLayout::NHWC || xLayout == DataLayout::NDHWC)
4258  {
4259  throw InvalidArgumentException(descriptorName +
4260  ": Invalid input tensor data layout combination.");
4261  }
4262  }
4263  }
4264 
4265  // Simulate aligning the ends of the matrix dims and prepending 1's to the beginning of the shorter one
4266  unsigned int outputTensorDimSize = std::max(inputXInfoAfterParams.GetNumDimensions(),
4267  inputYInfoAfterParams.GetNumDimensions());
4268  if(outputTensorDimSize-2 > 0)
4269  {
4270  TensorInfo tiXNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4272  TensorInfo tiYNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4274  TensorInfo tiOutNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4276 
4277  auto doAxisExtension = [&](std::vector<unsigned int> axisIndices, TensorInfo& ti)
4278  {
4279  auto sizeDiff = (outputTensorDimSize-2) - axisIndices.size();
4280 
4281  for(unsigned int i = 0; i < sizeDiff; i++)
4282  {
4283  axisIndices.insert(axisIndices.begin(), 1);
4284  }
4285 
4286  for(unsigned int i = 0; i < ti.GetNumDimensions(); i++)
4287  {
4288  ti.GetShape()[i] = inputXInfoAfterParams.GetShape()[i];
4289  }
4290  };
4291 
4292  auto axesXNotMul = BatchMatMulDescriptor::GetAxesNotMul(m_Parameters.m_DataLayoutX,
4293  inputXInfoAfterParams.GetShape());
4294  auto axesYNotMul = BatchMatMulDescriptor::GetAxesNotMul(m_Parameters.m_DataLayoutY,
4295  inputYInfoAfterParams.GetShape());
4296 
4297  doAxisExtension(axesXNotMul, tiXNotMul);
4298  doAxisExtension(axesYNotMul, tiYNotMul);
4299 
4300  for(unsigned int i = 0; i < tiOutNotMul.GetNumDimensions(); i++)
4301  {
4302  tiOutNotMul.GetShape()[i] = std::max(tiXNotMul.GetShape()[i],
4303  tiYNotMul.GetShape()[i]);
4304  }
4305 
4306  ValidateBroadcastTensorShapesMatch(tiXNotMul,
4307  tiYNotMul,
4308  tiOutNotMul,
4309  descriptorName,
4310  "input_X",
4311  "input_Y");
4312  }
4313 }
4314 
4315 
4316 } // namespace armnn
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 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
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
DataLayout
Definition: Types.hpp:62
unsigned int GetWidthIndex() const
std::vector< unsigned int > m_Origin
const TensorShape & GetShape() const
Definition: Tensor.hpp:191
constexpr bool IsQuantizedType()
Definition: TypesUtils.hpp:280
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 HasPerAxisQuantization() const
Definition: Tensor.cpp:446
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 ValidateTensorNumDimNumElem(const TensorInfo &tensorInfo, unsigned int numDimension, unsigned int numElements, std::string const &tensorName) const
void Validate(const WorkloadInfo &workloadInfo) const
Optional< unsigned int > GetQuantizationDim() const
Definition: Tensor.cpp:494
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
#define ARMNN_LOG(severity)
Definition: Logging.hpp:205
void ValidateInputsOutputs(const std::string &descName, unsigned int numExpectedIn, unsigned int numExpectedOut) const
Copyright (c) 2021 ARM Limited and Contributors.
void Validate(const WorkloadInfo &workloadInfo) const
SizeType GetSize() const
Definition: Types.hpp:338
void Validate(const WorkloadInfo &workloadInfo) const
static PermutationVector GetPermuteVec(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the axes which will be transposed.
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:451
bool HasMultipleQuantizationScales() const
Definition: Tensor.hpp:201
void Validate(const WorkloadInfo &workloadInfo) const
unsigned int GetHeightIndex() const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
constexpr const char * GetDataTypeName(DataType dataType)
Definition: TypesUtils.hpp:202
constexpr bool IsQuantized8BitType(DataType dataType)
Definition: TypesUtils.hpp:285
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< TensorInfo > m_InputTensorInfos
void Validate(const WorkloadInfo &workloadInfo) const
DataType
Definition: Types.hpp:48
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
void Validate(const WorkloadInfo &workloadInfo) const
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:478
static std::pair< std::vector< unsigned int >, std::vector< unsigned int > > GetAxesNotMul(const BatchMatMulDescriptor &desc, const TensorShape &inputXShape, const TensorShape &inputYShape)
float GetQuantizationScale() const
Definition: Tensor.cpp:461
Provides access to the appropriate indexes for Channels, Height and Width based on DataLayout...
DataType GetDataType() const
Definition: Tensor.hpp:198
bool has_value() const noexcept
Definition: Optional.hpp:53
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
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
static std::pair< std::pair< unsigned int, unsigned int >, std::pair< unsigned int, unsigned int > > GetAxesToMul(const BatchMatMulDescriptor &desc, const TensorShape &tensorXShape, const TensorShape &tensorYShape)
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< TensorInfo > m_OutputTensorInfos
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
#define CHECK_LOCATION()
Definition: Exceptions.hpp:203
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
DataType GetBiasDataType(DataType inputDataType)
void Validate(const WorkloadInfo &workloadInfo) const
void ValidateTensorNumDimensions(const TensorInfo &tensor, std::string const &descName, unsigned int numDimensions, std::string const &tensorName) 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
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< ITensorHandle * > m_Outputs
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
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::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:35
Contains information about TensorInfos of a layer.
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< ITensorHandle * > m_Inputs
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:195
unsigned int GetChannelsIndex() const
bool IsQuantized() const
Definition: Tensor.cpp:504
armnn::TensorShape Permuted(const armnn::TensorShape &srcShape, const armnn::PermutationVector &mappings)
Definition: Permute.cpp:98
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
unsigned int GetNumElements() const
Definition: Tensor.hpp:196
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< unsigned int > m_Origin