ArmNN
 21.08
WorkloadData.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
11 #include <armnn/Logging.hpp>
12 
13 #include <algorithm>
14 #include <iomanip>
15 #include <string>
16 #include <sstream>
17 
18 #include <fmt/format.h>
19 
20 using namespace armnnUtils;
21 
22 namespace armnn
23 {
24 
25 //---------------------------------------------------------------
27 {
28  switch (inputDataType)
29  {
30  case DataType::Float16:
31  return DataType::Float16;
32  case DataType::BFloat16:
33  case DataType::Float32:
34  return DataType::Float32;
35  case DataType::QAsymmS8:
36  return DataType::Signed32;
37  case DataType::QAsymmU8:
38  return DataType::Signed32;
39  case DataType::QSymmS8:
40  return DataType::Signed32;
41  case DataType::QSymmS16:
42  return DataType::Signed32;
43  default:
44  ARMNN_ASSERT_MSG(false, "Invalid input data type");
45  return DataType::Float32;
46  }
47 }
48 
49 namespace
50 {
51 
52 //---------------------------------------------------------------
53 //android ndk does not support std::to_string function.
54 template <typename T>
55 std::string to_string(T value)
56 {
57  std::ostringstream os;
58  os << value;
59  return os.str();
60 }
61 
62 //---------------------------------------------------------------
63 void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName)
64 {
65  if (!ptr)
66  {
67  throw InvalidArgumentException(descName + ": Invalid null pointer. The " +
68  paramName + " parameter must be set.");
69  }
70 }
71 
72 //---------------------------------------------------------------
73 void ValidateTensorShapesMatch(const TensorInfo& first,
74  const TensorInfo& second,
75  std::string const& descName,
76  std::string const& firstName,
77  std::string const& secondName)
78 {
79  if (first.GetShape() != second.GetShape())
80  {
81  throw InvalidArgumentException(descName + ": "
82  + firstName + " & " + secondName + " must have identical shapes");
83  }
84 }
85 
86 //---------------------------------------------------------------
87 void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
88 {
89  if (workloadInfo.m_InputTensorInfos.size() != expectedSize)
90  {
91  throw InvalidArgumentException(descName +
92  ": Requires exactly " + to_string(expectedSize) + "input(s). " +
93  to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided.");
94  }
95 }
96 
97 //---------------------------------------------------------------
98 void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
99 {
100  if (workloadInfo.m_OutputTensorInfos.size() != expectedSize)
101  {
102  throw InvalidArgumentException(descName +
103  ": Requires exactly " + to_string(expectedSize) + " output(s). " +
104  to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
105  }
106 }
107 
108 //---------------------------------------------------------------
109 void ValidateTensorNumDimensions(const TensorInfo& tensor,
110  std::string const& descName,
111  unsigned int numDimensions,
112  std::string const& tensorName)
113 {
114  if (tensor.GetNumDimensions() != numDimensions)
115  {
116  throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " +
117  to_string(tensor.GetNumDimensions()) + " dimensions for " +
118  tensorName + " tensor.");
119  }
120 }
121 
122 //---------------------------------------------------------------
123 void ValidateTensorNumElements(const TensorInfo& tensor,
124  std::string const& descName,
125  unsigned int numElements,
126  std::string const& tensorName)
127 {
128  if (tensor.GetNumElements() != numElements)
129  {
130  throw InvalidArgumentException(descName + ": Expected " + to_string(numElements) + " but got " +
131  to_string(tensor.GetNumElements()) + " elements for " +
132  tensorName + " tensor.");
133  }
134 }
135 
136 //---------------------------------------------------------------
137 void ValidateTensorNumDimNumElem(const TensorInfo& tensorInfo,
138  unsigned int numDimension,
139  unsigned int numElements,
140  std::string const& tensorName)
141 {
142  const std::string functionName{"ValidateTensorNumDimNumElem"};
143  ValidateTensorNumDimensions(tensorInfo, functionName, numDimension, tensorName);
144  ValidateTensorNumElements(tensorInfo, functionName, numElements, tensorName);
145 }
146 
147 //---------------------------------------------------------------
148 void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
149  const std::string& descName, std::string const& tensorName)
150 {
151  if (tensor.GetDataType() != dataType)
152  {
153  throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
154  GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
155  }
156 }
157 
158 void ValidPerAxisQuantizedDataType(const TensorInfo& tensor, const std::string& descName, const std::string& tensorName)
159 {
161  if (tensor.GetDataType() != DataType::QSymmS8 &&
162  tensor.GetDataType() != DataType::QuantizedSymm8PerAxis)
163  {
164  throw InvalidArgumentException(descName +
165  ": Expected data type which supports per-axis quantization scheme but got " +
166  GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
167  }
169 }
170 
171 //---------------------------------------------------------------
172 void ValidateTensorQuantizationSpace(const TensorInfo& first,
173  const TensorInfo& second,
174  const std::string& descName,
175  std::string const& firstName,
176  std::string const& secondName)
177 {
178  if (!first.IsQuantized() ||
179  !second.IsQuantized())
180  {
181  // Not a quantized type, ignore the validation
182  return;
183  }
184 
185  DataType firstDataType = first.GetDataType();
186  DataType secondDataType = second.GetDataType();
187 
188  if (firstDataType != secondDataType)
189  {
190  throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
191  " must be of the same quantized type, " +
192  firstName + " is " + GetDataTypeName(firstDataType) + ", " +
193  secondName + " is " + GetDataTypeName(secondDataType));
194  }
195 
196  if (!first.IsTypeSpaceMatch(second))
197  {
198  throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
199  " must have the same quantization space, " +
200  firstName + " has offset " + to_string(first.GetQuantizationOffset()) +
201  " and scale " + to_string(first.GetQuantizationScale()) + ", " +
202  secondName + " has offset " + to_string(second.GetQuantizationOffset()) +
203  " and scale " + to_string(second.GetQuantizationScale()));
204  }
205 }
206 
207 //---------------------------------------------------------------
208 void ValidateBiasTensorQuantization(const TensorInfo& biasTensor,
209  const TensorInfo& inputTensorInfo,
210  const TensorInfo& weightsTensorInfo,
211  const std::string& descName)
212 {
213  // Helper lambda function to validate a single bias quantization scale value
214  auto VerifyBiasQuantizationScale = [&descName](float biasScale, float expectedScale) -> void
215  {
216  constexpr float tolerance = 0.0001f;
217  if (std::abs(biasScale - expectedScale) > tolerance)
218  {
219  // Print the float values with extra precision to see very small differences
220  ARMNN_LOG(warning) << std::setprecision(6) << descName << ": Expected " << expectedScale <<
221  " for bias quantization scale (product of input and weight scales), but got " <<
222  biasScale << ". Using scale provided.";
223  }
224  };
225 
226  if (biasTensor.GetQuantizationOffset() != 0)
227  {
228  throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
229  to_string(biasTensor.GetQuantizationOffset()));
230  }
231 
232  if (biasTensor.HasMultipleQuantizationScales() || weightsTensorInfo.HasMultipleQuantizationScales())
233  {
234  // Validate per-axis quantization scales
235  const std::vector<float>& weightScales = weightsTensorInfo.GetQuantizationScales();
236  const std::vector<float>& biasScales = biasTensor.GetQuantizationScales();
237 
238  if (weightScales.size() != biasScales.size())
239  {
240  std::stringstream msg;
241  msg << descName << ": Expected matching number of per-axis quantization scales for weights and bias, "
242  << "but got different values. This is currently unsupported: weights=" << weightScales.size()
243  << ", biases=" << biasScales.size();
244  throw InvalidArgumentException(msg.str(), CHECK_LOCATION());
245  }
246 
247  for (size_t i = 0ul; i < biasScales.size(); ++i)
248  {
249  const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightScales[i];
250  VerifyBiasQuantizationScale(biasScales[i], expectedScale);
251  }
252  }
253  else
254  {
255  // Validate per-tensor quantization scale
256  const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightsTensorInfo.GetQuantizationScale();
257  VerifyBiasQuantizationScale(biasTensor.GetQuantizationScale(), expectedScale);
258  }
259 }
260 
261 //---------------------------------------------------------------
262 void ValidateTensors(const std::vector<ITensorHandle*>& vec,
263  unsigned int numExpected,
264  const std::string& descName,
265  const std::string& varName)
266 {
267  if (vec.empty() && numExpected > 0)
268  {
269  throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
270  }
271 
272  for (unsigned int i = 0; i < numExpected; ++i)
273  {
274  if (!vec[i])
275  {
276  throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
277  }
278  }
279 }
280 
281 //---------------------------------------------------------------
282 void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
283  const TensorInfo& second,
284  const TensorInfo& output,
285  std::string const& descName,
286  std::string const& firstName,
287  std::string const& secondName)
288 {
289  // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
290  // broadcasted.
291  if (first.GetNumDimensions() != second.GetNumDimensions())
292  {
293  throw InvalidArgumentException(descName + ": Tensors "
294  + firstName + " & " + secondName
295  + " must have the same number of dimensions in order to be broadcasted");
296  }
297  uint32_t numDims = first.GetNumDimensions();
298  std::vector<uint32_t> outputDims(numDims, 0u);
299  for (uint32_t i = 0; i < numDims; i++)
300  {
301  const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i];
302  const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1);
303  if (dimsNotEqual && dimsNotOne)
304  {
305  throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes");
306  }
307  outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]);
308  }
309  TensorShape broadcastShape = TensorShape(armnn::numeric_cast<unsigned int>(outputDims.size()), outputDims.data());
310  if (broadcastShape != output.GetShape())
311  {
312  throw InvalidArgumentException(descName + ": The tensor shape resulting from adding "
313  + firstName + " & " + secondName
314  + " does not match the output shape");
315  }
316 }
317 
318 //---------------------------------------------------------------
319 void ValidateDataTypes(const TensorInfo& info,
320  const std::vector<armnn::DataType>& supportedTypes,
321  std::string const& descName)
322 {
323  auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
324  if (iterator == supportedTypes.end())
325  {
326  throw InvalidArgumentException(descName + ": " + " Tensor type is not supported.");
327  }
328 }
329 
330 //---------------------------------------------------------------
331 void ValidateTensorDataTypesMatch(const TensorInfo& first,
332  const TensorInfo& second,
333  std::string const& descName,
334  std::string const& firstName,
335  std::string const& secondName)
336 {
337  if (first.GetDataType() != second.GetDataType())
338  {
339  throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
340  " must have identical data types.");
341  }
342 }
343 
344 //---------------------------------------------------------------
345 void ValidateTensorNumElementsMatch(const TensorInfo& first,
346  const TensorInfo& second,
347  std::string const& descName,
348  std::string const& firstName,
349  std::string const& secondName)
350 {
351  if (first.GetNumElements() != second.GetNumElements())
352  {
353  throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
354  " must have the same number of elements.");
355  }
356 }
357 
358 void ValidateWeightDataType(const TensorInfo& inputInfo,
359  const TensorInfo& weightInfo,
360  const std::string& descName)
361 {
362  const DataType inputType = inputInfo.GetDataType();
363  if (IsQuantized8BitType(inputType))
364  {
366  const std::vector<DataType> validTypes =
367  {
368  DataType::QAsymmS8,
369  DataType::QAsymmU8,
370  DataType::QSymmS8,
371  DataType::QuantizedSymm8PerAxis // deprecated
372  };
374 
375  ValidateDataTypes(weightInfo, validTypes, descName);
376  }
377  else
378  {
379  ValidateTensorDataTypesMatch(inputInfo, weightInfo, descName, "input", "weight");
380  }
381 }
382 
383 void ValidatePerAxisQuantizationDimension(const TensorInfo& tensorInfo,
384  const std::string& descName,
385  const std::string& tensorName)
386 {
387  const Optional<unsigned int>& quantizationDim = tensorInfo.GetQuantizationDim();
388  if (!quantizationDim.has_value())
389  {
390  throw InvalidArgumentException(fmt::format("{0}: Quantization dimension for per-axis quantization "
391  "not set on tensor {1}.", descName, tensorName));
392  }
393 }
394 
395 void ValidatePerAxisQuantizationOffset(const TensorInfo& tensorInfo,
396  const std::string& descName,
397  const std::string& tensorName)
398 {
399  int32_t quantizationOffset = tensorInfo.GetQuantizationOffset();
400  if (quantizationOffset != 0)
401  {
402  throw InvalidArgumentException(fmt::format(
403  "{0}: Quantization offset for per-axis quantization expected to be 0 on tensor {1}, but got: {2}",
404  descName, tensorName, quantizationOffset));
405  }
406 }
407 
408 void ValidatePerAxisQuantization(const TensorInfo& inputInfo,
409  const TensorInfo& outputInfo,
410  const TensorInfo& weightInfo,
411  const Optional<TensorInfo>& optionalBiasInfo,
412  const std::string& descName)
413 {
414  if (weightInfo.HasPerAxisQuantization())
415  {
416  const DataType inputDataType = inputInfo.GetDataType();
417  const DataType outputDataType = outputInfo.GetDataType();
418 
419  const bool canHavePerAxisQuantization = (IsQuantized8BitType(inputDataType)) && inputDataType == outputDataType;
420 
421  if (!canHavePerAxisQuantization)
422  {
423  throw InvalidArgumentException(fmt::format(
424  "{0}: Per-axis quantization parameters set on tensor {1}, but data type does not support "
425  "per-axis quantization.", descName, "weight"));
426  }
427 
428 
429  ValidPerAxisQuantizedDataType(weightInfo, descName, "weight");
430  ValidatePerAxisQuantizationDimension(weightInfo, descName, "weight");
431  ValidatePerAxisQuantizationOffset(weightInfo, descName, "weight");
432 
433  if (optionalBiasInfo.has_value())
434  {
435  const TensorInfo& biasInfo = optionalBiasInfo.value();
436  if (!biasInfo.HasPerAxisQuantization())
437  {
438  throw InvalidArgumentException(fmt::format(
439  "{}: Per-axis quantization parameters not set on bias tensor, "
440  "despite being set on weight tensor.", descName));
441  }
442 
443  ValidateTensorDataType(biasInfo, DataType::Signed32, descName, "bias");
444  ValidatePerAxisQuantizationDimension(biasInfo, descName, "bias");
445  ValidatePerAxisQuantizationOffset(biasInfo, descName, "bias");
446  }
447  }
448 }
449 
450 } // anonymous namespace
451 
452 void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
453  unsigned int numExpectedIn, unsigned int numExpectedOut) const
454 {
455  ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
456  ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
457 }
458 
459 //---------------------------------------------------------------
460 void MapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
461 {
462  const std::string descriptorName{"MapQueueDescriptor"};
463 
464  ValidateNumInputs(workloadInfo, descriptorName, 1);
465  ValidateNumOutputs(workloadInfo, descriptorName, 0);
466 
467  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
468  {
469  if (!m_Inputs[i])
470  {
472  fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
473  }
474  }
475 }
476 
477 //---------------------------------------------------------------
478 void UnmapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
479 {
480  const std::string descriptorName{"UnmapQueueDescriptor"};
481 
482  ValidateNumInputs(workloadInfo, descriptorName, 1);
483  ValidateNumOutputs(workloadInfo, descriptorName, 0);
484 
485  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
486  {
487  if (!m_Inputs[i])
488  {
490  fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
491  }
492  }
493 }
494 
495 //---------------------------------------------------------------
496 void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
497 {
498  const std::string descriptorName{"MemCopyQueueDescriptor"};
499 
500  ValidateNumInputs(workloadInfo, descriptorName, 1);
501  ValidateNumOutputs(workloadInfo, descriptorName , 1);
502 
503  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
504  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
505 
506  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
507  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
508 
509  if (m_Inputs.size() != m_Outputs.size())
510  {
511  throw InvalidArgumentException(fmt::format(
512  "{0}: Number of inputs ({1}) does not match the number of outputs ({2}).",
513  descriptorName, m_Inputs.size(), m_Outputs.size()));
514  }
515 
516  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
517  {
518  if (!m_Inputs[i])
519  {
520  throw InvalidArgumentException(fmt::format(
521  "{0}: Invalid NULL input {1}.", descriptorName, i));
522  }
523 
524  if (!m_Outputs[i])
525  {
526  throw InvalidArgumentException(fmt::format("{0}: Invalid NULL output {1}", descriptorName, i));
527  }
528  }
529 }
530 
531 //---------------------------------------------------------------
532 void MemImportQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
533 {
534  ValidateNumInputs(workloadInfo, "MemImportQueueDescriptor", 1);
535  ValidateNumOutputs(workloadInfo, "MemImportQueueDescriptor" , 1);
536 
537  if (workloadInfo.m_InputTensorInfos.size() != 1)
538  {
539  throw InvalidArgumentException(fmt::format("Number of input infos ({}) is not 1.",
540  workloadInfo.m_InputTensorInfos.size()));
541 
542  }
543 
544  if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
545  {
546  throw InvalidArgumentException(fmt::format(
547  "Number of input infos ({0}) does not match the number of output infos ({1})",
548  workloadInfo.m_InputTensorInfos.size(), workloadInfo.m_OutputTensorInfos.size()));
549  }
550 
551  for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
552  {
553  if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
554  workloadInfo.m_OutputTensorInfos[i].GetNumElements())
555  {
556  throw InvalidArgumentException(fmt::format(
557  "Number of elements for tensor input and output {} does not match", i ));
558  }
559  }
560 
561  if (m_Inputs.size() != 1)
562  {
563  throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
564  }
565 
566  if (m_Inputs.size() != m_Outputs.size())
567  {
568  throw InvalidArgumentException(fmt::format(
569  "Number of inputs ({0}) does not match the number of outputs ({1})",
570  m_Inputs.size(), m_Outputs.size()));
571  }
572 
573  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
574  {
575  if (!m_Inputs[i])
576  {
577  throw InvalidArgumentException(fmt::format("Invalid null input {}", i));
578  }
579 
580  if (!m_Outputs[i])
581  {
582  throw InvalidArgumentException(fmt::format("Invalid null output {}", i));
583  }
584  }
585 }
586 
587 //---------------------------------------------------------------
588 void MemSyncQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
589 {
590  ValidateNumInputs(workloadInfo, "MemSyncQueueDescriptor", 1);
591  ValidateNumOutputs(workloadInfo, "MemSyncQueueDescriptor" , 1);
592 
593  if (m_Inputs.size() != 1)
594  {
595  throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
596  }
597 
598  if (m_Outputs.size() != 0)
599  {
600  throw InvalidArgumentException(fmt::format("Number of outputs ({}) is not 0.", m_Outputs.size()));
601  }
602 
603  if (!m_Inputs[0])
604  {
605  throw InvalidArgumentException(fmt::format("Invalid null input 0"));
606  }
607 }
608 
609 //---------------------------------------------------------------
610 void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
611 {
612  const std::string descriptorName{"ActivationQueueDescriptor"};
613 
614  ValidateNumInputs(workloadInfo, descriptorName, 1);
615  ValidateNumOutputs(workloadInfo, descriptorName, 1);
616 
617  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
618  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
619 
620  std::vector<DataType> supportedTypes =
621  {
628  };
629 
630  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
631  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
632  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
633 }
634 
635 void ArgMinMaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
636 {
637  const std::string descriptorName{"ArgMinMaxQueueDescriptor"};
638 
639  ValidateNumInputs(workloadInfo, descriptorName, 1);
640  ValidateNumOutputs(workloadInfo, descriptorName, 1);
641 
642  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
643  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
644 
645  if (outputTensorInfo.GetDataType() != DataType::Signed32 &&
646  outputTensorInfo.GetDataType() != DataType::Signed64)
647  {
648  throw InvalidArgumentException(descriptorName + ": Output of ArgMinMax layer must be Int32 or Int64.");
649  }
650 
651  std::vector<DataType> supportedInputTypes =
652  {
661  };
662 
663  ValidateDataTypes(inputTensorInfo, supportedInputTypes, descriptorName);
664 
665  auto inputShape = inputTensorInfo.GetShape();
666  auto outputShape = outputTensorInfo.GetShape();
667 
668  auto inputNumDimensions = inputShape.GetNumDimensions();
669  auto unsignedAxis = armnnUtils::GetUnsignedAxis(inputNumDimensions, m_Parameters.m_Axis);
670 
671  const std::string outputShapeError{": Output tensor shape does not match shape inferred from input tensor."};
672 
673  // 1D input shape results in scalar output shape
674  if (inputShape.GetNumDimensions() == 1)
675  {
676  if (outputShape.GetNumDimensions() != 1 && outputShape[0] != 1)
677  {
678  throw InvalidArgumentException(descriptorName + outputShapeError);
679  }
680  }
681  else
682  {
683  for (unsigned int i = 0; i < unsignedAxis; ++i)
684  {
685  if (outputShape[i] != inputShape[i])
686  {
687  throw InvalidArgumentException(descriptorName + outputShapeError);
688  }
689  }
690 
691  for (auto i = unsignedAxis + 1; i < inputNumDimensions; ++i)
692  {
693  if (outputShape[i - 1] != inputShape[i])
694  {
695  throw InvalidArgumentException(descriptorName + outputShapeError);
696  }
697  }
698  }
699 }
700 
701 void CastQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
702 {
703  const std::string descriptorName{"CastQueueDescriptor"};
704 
705  ValidateNumInputs(workloadInfo, descriptorName, 1);
706  ValidateNumOutputs(workloadInfo, descriptorName, 1);
707 
708  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
709  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
710 
711  std::vector<DataType> supportedTypes =
712  {
722  };
723 
724  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
725  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
726 }
727 
728 void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
729 {
730  const std::string descriptorName{"SoftmaxQueueDescriptor"};
731 
732  ValidateNumInputs(workloadInfo, descriptorName, 1);
733  ValidateNumOutputs(workloadInfo, descriptorName, 1);
734 
735  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
736  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
737 
738  std::vector<DataType> supportedTypes =
739  {
746  };
747 
748  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
749  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
750  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
751 }
752 
753 void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
754 {
755  const std::string descriptorName{"SplitterQueueDescriptor"};
756 
757  ValidateNumInputs(workloadInfo, descriptorName, 1);
758 
759  // Check the supported data types
760  std::vector<DataType> supportedTypes =
761  {
770  };
771 
772  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
773  for (unsigned long i = 0ul; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
774  {
775  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[i];
776  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
777 
778  const std::string outputName = "output_" + std::to_string(i);
779  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", outputName);
780  }
781 
782  if (workloadInfo.m_OutputTensorInfos.size() <= 0)
783  {
784  throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
785  }
786 
787  if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
788  {
790  descriptorName + ": Number of split windows "
791  "has to match number of workloadInfo.m_OutputTensorInfos. "
792  "Number of windows: " +
793  to_string(m_ViewOrigins.size()) +
794  ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
795  }
796 
797  //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
798  std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
799  for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
800  {
801  //Checks that the dimensionality of input is same as the split windows.
802  ViewOrigin const& e = m_ViewOrigins[w];
803  if (e.m_Origin.size() != inputDims)
804  {
805  throw InvalidArgumentException(descriptorName + ": Window origin have to "
806  "have the same dimensionality as the input tensor. "
807  "Window origin (index: " +
808  to_string(w) + ") has " + to_string(e.m_Origin.size()) +
809  " dimensions, the input "
810  "tensor has " +
811  to_string(inputDims) + " dimensions.");
812  }
813  for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
814  {
815  if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
816  workloadInfo.m_InputTensorInfos[0].GetShape()[i])
817  {
818  throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
819  "be smaller or equal than the size of the input in that coord.");
820  }
821  }
822  }
823 }
824 
825 void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
826 {
827  const std::string descriptorName{"ConcatQueueDescriptor"};
828 
829  ValidateNumOutputs(workloadInfo, descriptorName, 1);
830 
831  if (m_Inputs.size() <= 0)
832  {
833  throw InvalidArgumentException(descriptorName + ": At least one input needs to be provided.");
834  }
835  if (m_Outputs.size() <= 0)
836  {
837  throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
838  }
839 
840  if (workloadInfo.m_InputTensorInfos.size() <= 0)
841  {
842  throw InvalidArgumentException(descriptorName + ": At least one TensorInfo input needs to be provided.");
843  }
844  if (workloadInfo.m_OutputTensorInfos.size() <= 0)
845  {
846  throw InvalidArgumentException(descriptorName + ": At least one TensorInfo output needs to be provided.");
847  }
848 
849  if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
850  {
851  throw InvalidArgumentException(descriptorName + ": Invalid concatenation axis provided.");
852  }
853 
854  if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
855  {
856  return;
857  }
858 
859  if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
860  {
862  descriptorName + ": Number of split windows "
863  "has to match number of workloadInfo.m_InputTensorInfos. "
864  "Number of windows: " +
865  to_string(m_ViewOrigins.size()) +
866  ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
867  }
868 
869  //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
870  std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
871  for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
872  {
873  //Checks that the dimensionality of output is same as the split windows.
874  ViewOrigin const& e = m_ViewOrigins[w];
875  if (e.m_Origin.size() != outputDims)
876  {
877  throw InvalidArgumentException(descriptorName + ": Window origin have to "
878  "have the same dimensionality as the output tensor. "
879  "Window origin (index: " +
880  to_string(w) + ") has " + to_string(e.m_Origin.size()) +
881  " dimensions, the output "
882  "tensor has " +
883  to_string(outputDims) + " dimensions.");
884  }
885  //Checks that the merge windows are within the output tensor.
886  for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
887  {
888  if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
889  > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
890  {
891  throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
892  "be smaller or equal than the size of the output in that coord.");
893  }
894  }
895  }
896 
897  // Check the supported data types
898  std::vector<DataType> supportedTypes =
899  {
908  };
909 
910  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
911  for (unsigned long i = 0ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
912  {
913  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[i];
914  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
915 
916  const std::string inputName = "input_" + std::to_string(i);
917  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, inputName, "output");
918  }
919 }
920 
921 void StackQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
922 {
923  const std::string descriptorName{"StackQueueDescriptor"};
924 
925  ValidateNumOutputs(workloadInfo, descriptorName, 1);
926 
927  if (m_Parameters.m_NumInputs != workloadInfo.m_InputTensorInfos.size())
928  {
929  throw InvalidArgumentException(descriptorName + ": Must have the defined number of input tensors.");
930  }
931 
932  // All inputs must have the same shape, which is defined in parameters
933  const TensorShape& inputShape = m_Parameters.m_InputShape;
934  for (unsigned int i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
935  {
936  if (workloadInfo.m_InputTensorInfos[i].GetShape() != inputShape)
937  {
938  throw InvalidArgumentException(descriptorName + ": All input tensor shapes must match the defined shape.");
939  }
940  }
941 
942  if (inputShape.GetNumDimensions() > 4)
943  {
944  throw InvalidArgumentException(descriptorName + ": Input tensor may have up to 4 dimensions.");
945  }
946 
947  // m_Axis is 0-based and may take values from 0 to the number of input dimensions (inclusive),
948  // since the output tensor has an additional dimension.
949  if (m_Parameters.m_Axis > inputShape.GetNumDimensions())
950  {
951  throw InvalidArgumentException(descriptorName + ": Axis may not be greater "
952  "than the number of input dimensions.");
953  }
954 
955  // Output shape must be as inferred from the input shape
956  const TensorShape& outputShape = workloadInfo.m_OutputTensorInfos[0].GetShape();
957  for (unsigned int i = 0; i < m_Parameters.m_Axis; ++i)
958  {
959  if (outputShape[i] != inputShape[i])
960  {
961  throw InvalidArgumentException(descriptorName + ": Output tensor must "
962  "match shape inferred from input tensor.");
963  }
964  }
965 
966  if (outputShape[m_Parameters.m_Axis] != m_Parameters.m_NumInputs)
967  {
968  throw InvalidArgumentException(descriptorName + ": Output tensor must "
969  "match shape inferred from input tensor.");
970  }
971 
972  for (unsigned int i = m_Parameters.m_Axis + 1; i < inputShape.GetNumDimensions() + 1; ++i)
973  {
974  if (outputShape[i] != inputShape[i-1])
975  {
976  throw InvalidArgumentException(descriptorName + ": Output tensor must "
977  "match shape inferred from input tensor.");
978  }
979  }
980 
981  if (outputShape.GetNumDimensions() > 5)
982  {
983  throw InvalidArgumentException(descriptorName + ": Output tensor may have up to 5 dimensions.");
984  }
985 
986  // Check the supported data types
987  std::vector<DataType> supportedTypes =
988  {
997  };
998 
999  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
1000 
1001  for (unsigned int i = 1ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
1002  {
1003  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1004  workloadInfo.m_InputTensorInfos[i],
1005  descriptorName,
1006  "input_0",
1007  "input_" + std::to_string(i));
1008  }
1009 
1010  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1011  workloadInfo.m_OutputTensorInfos[0],
1012  descriptorName,
1013  "input_0",
1014  "output");
1015 }
1016 
1017 void FillQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1018 {
1019  const std::string descriptorName{"FillQueueDescriptor"};
1020 
1021  ValidateNumInputs(workloadInfo, descriptorName, 1);
1022  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1023 
1024  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1025  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1026 
1027  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 1, "input");
1028 
1029  std::vector<DataType> supportedTypes =
1030  {
1035  };
1036 
1037  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1038 }
1039 
1041 {
1042  const std::string descriptorName{"FullyConnectedQueueDescriptor"};
1043 
1044  uint32_t numInputs = 2;
1045  if (m_Parameters.m_BiasEnabled)
1046  {
1047  numInputs = 3;
1048  }
1049 
1050  ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1051  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1052 
1053  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1054  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1055 
1056  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1057 
1058  if (!(inputTensorInfo.GetNumDimensions() == 2 || inputTensorInfo.GetNumDimensions() == 4))
1059  {
1060  throw InvalidArgumentException(descriptorName + ": Input tensor must have 2 or 4 dimensions.");
1061  }
1062 
1063  TensorInfo weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1064  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 2, "weight");
1065 
1066  if (m_Parameters.m_BiasEnabled)
1067  {
1068  TensorInfo biasTensorInfo = workloadInfo.m_InputTensorInfos[2];
1069  // Validates type and quantization values.
1070  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1071  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1072  ValidateTensorNumDimensions(biasTensorInfo, descriptorName, 1, "bias");
1073  }
1074 
1075  // Check the supported data types
1076  std::vector<DataType> supportedTypes =
1077  {
1084  };
1085 
1086  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1087 
1088  // For FullyConnected, we allow to have BFloat16 input with Float32 output for optimization.
1089  if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1090  {
1091  if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1092  {
1093  throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1094  "for BFloat16 input.");
1095  }
1096  }
1097  else
1098  {
1099  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1100  }
1101 }
1102 
1104 {
1105  const std::string descriptorName{"NormalizationQueueDescriptor"};
1106 
1107  ValidateNumInputs(workloadInfo, descriptorName, 1);
1108  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1109 
1110  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1111  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1112 
1113  // Check the supported data types
1114  std::vector<DataType> supportedTypes =
1115  {
1122  };
1123 
1124  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1125 
1126  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1127 
1128  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1129 }
1130 
1131 void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1132 {
1133  const std::string descriptorName{"AdditionQueueDescriptor"};
1134 
1135  ValidateNumInputs(workloadInfo, descriptorName, 2);
1136  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1137 
1138  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1139  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1140  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1141 
1142  std::vector<DataType> supportedTypes =
1143  {
1151  };
1152 
1153  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1154  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1155  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1156 
1157  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1158  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1159 
1160  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1161  inputTensorInfo1,
1162  outputTensorInfo,
1163  descriptorName,
1164  "input_0",
1165  "input_1");
1166 }
1167 
1169 {
1170  const std::string descriptorName{"MultiplicationQueueDescriptor"};
1171 
1172  ValidateNumInputs(workloadInfo, descriptorName, 2);
1173  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1174 
1175  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1176  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1177  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1178 
1179  std::vector<DataType> supportedTypes =
1180  {
1188  };
1189 
1190  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1191  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1192  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1193 
1194  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1195  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1196 
1197  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1198  inputTensorInfo1,
1199  outputTensorInfo,
1200  descriptorName,
1201  "input_0",
1202  "input_1");
1203 }
1204 
1206 {
1207  const std::string descriptorName{"BatchNormalizationQueueDescriptor"};
1208 
1209  ValidateNumInputs(workloadInfo, descriptorName, 1);
1210  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1211 
1212  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1213  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1214 
1215  std::vector<DataType> supportedTypes =
1216  {
1223  };
1224 
1225  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1226  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1227 
1228  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1229  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1230 
1231  ValidatePointer(m_Mean, descriptorName, "mean");
1232  ValidatePointer(m_Variance, descriptorName, "variance");
1233  ValidatePointer(m_Beta, descriptorName, "beta");
1234  ValidatePointer(m_Gamma, descriptorName, "gamma");
1235 
1236  const TensorInfo& mean = m_Mean->GetTensorInfo();
1237  const TensorInfo& variance = m_Variance->GetTensorInfo();
1238  const TensorInfo& beta = m_Beta->GetTensorInfo();
1239  const TensorInfo& gamma = m_Gamma->GetTensorInfo();
1240 
1241  ValidateTensorNumDimensions(mean, descriptorName, 1, "mean");
1242  ValidateTensorNumDimensions(variance, descriptorName, 1, "variance");
1243  ValidateTensorNumDimensions(beta, descriptorName, 1, "beta");
1244  ValidateTensorNumDimensions(gamma, descriptorName, 1, "gamma");
1245 
1246  ValidateTensorShapesMatch(mean, variance, descriptorName, "mean", "variance");
1247  ValidateTensorShapesMatch(mean, beta, descriptorName, "mean", "beta");
1248  ValidateTensorShapesMatch(mean, gamma, descriptorName, "mean", "gamma");
1249 }
1250 
1252 {
1253  const std::string descriptorName{"Convolution2dQueueDescriptor"};
1254 
1255  ValidateNumInputs(workloadInfo, descriptorName, 1);
1256  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1257 
1258  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1259  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1260 
1261  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1262  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1263 
1264  ValidatePointer(m_Weight, descriptorName, "weight");
1265 
1266  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
1267  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1268 
1269  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1270 
1271  Optional<TensorInfo> optionalBiasTensorInfo;
1272  if (m_Parameters.m_BiasEnabled)
1273  {
1274  ValidatePointer(m_Bias, descriptorName, "bias");
1275 
1276  optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
1277  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1278 
1279  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1280  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1281  }
1282 
1283  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1284  {
1286  fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1287  "cannot be either negative or 0.",
1288  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1289  }
1290 
1291  ValidatePerAxisQuantization(inputTensorInfo,
1292  outputTensorInfo,
1293  weightTensorInfo,
1294  optionalBiasTensorInfo,
1295  descriptorName);
1296 
1297  std::vector<DataType> supportedTypes =
1298  {
1306  };
1307 
1308  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1309 
1310  // For Convolution2d, we allow to have BFloat16 input with Float32 output for optimization.
1311  if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1312  {
1313  if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1314  {
1315  throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1316  "for BFloat16 input.");
1317  }
1318  }
1319  else
1320  {
1321  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1322  }
1323 }
1324 
1326 {
1327  const std::string descriptorName{"DepthwiseConvolution2dQueueDescriptor"};
1328 
1329  ValidateNumInputs(workloadInfo, descriptorName, 1);
1330  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1331 
1332  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1333  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1334 
1335  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1336  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1337 
1338  ValidatePointer(m_Weight, descriptorName, "weight");
1339 
1340  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
1341  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1342 
1343  if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 )
1344  {
1346  fmt::format("{}: dilationX (provided {}) and dilationY (provided {}) "
1347  "cannot be smaller than 1.",
1348  descriptorName, m_Parameters.m_DilationX, m_Parameters.m_DilationX));
1349  }
1350 
1351  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1352  {
1354  fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1355  "cannot be either negative or 0.",
1356  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1357  }
1358 
1359  const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
1360 
1361  // Expected weight shape: [ 1, H, W, I*M ] - This shape does NOT depend on the data layout
1362  // inputChannels * channelMultiplier should be equal to outputChannels.
1363  const unsigned int numWeightOutputChannels = weightTensorInfo.GetShape()[3]; // I*M=Cout
1364  const unsigned int numOutputChannels = outputTensorInfo.GetShape()[channelIndex];
1365  if (numWeightOutputChannels != numOutputChannels)
1366  {
1367  throw InvalidArgumentException(fmt::format(
1368  "{0}: The weight format in armnn is expected to be [1, H, W, Cout]."
1369  "But 4th dimension is not equal to Cout. Cout = {1} Provided weight shape: [{2}, {3}, {4}, {5}]",
1370  descriptorName,
1371  numOutputChannels,
1372  weightTensorInfo.GetShape()[0],
1373  weightTensorInfo.GetShape()[1],
1374  weightTensorInfo.GetShape()[2],
1375  weightTensorInfo.GetShape()[3]));
1376  }
1377  if (weightTensorInfo.GetShape()[0] != 1)
1378  {
1379  throw InvalidArgumentException(fmt::format(
1380  "{0}: The weight format in armnn is expected to be [1, H, W, Cout]."
1381  "But first dimension is not equal to 1. Provided weight shape: [{1}, {2}, {3}, {4}]",
1382  descriptorName,
1383  weightTensorInfo.GetShape()[0],
1384  weightTensorInfo.GetShape()[1],
1385  weightTensorInfo.GetShape()[2],
1386  weightTensorInfo.GetShape()[3]));
1387  }
1388 
1389  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1390 
1391  Optional<TensorInfo> optionalBiasTensorInfo;
1392  if (m_Parameters.m_BiasEnabled)
1393  {
1394  ValidatePointer(m_Bias, descriptorName, "bias");
1395 
1396  optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
1397  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1398 
1399  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1400  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1401  }
1402  ValidatePerAxisQuantization(inputTensorInfo,
1403  outputTensorInfo,
1404  weightTensorInfo,
1405  optionalBiasTensorInfo,
1406  descriptorName);
1407 
1408  std::vector<DataType> supportedTypes =
1409  {
1416  };
1417 
1418  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1419  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1420 }
1421 
1422 void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1423 {
1424  const std::string descriptorName{"PermuteQueueDescriptor"};
1425 
1426  ValidateNumInputs(workloadInfo, descriptorName, 1);
1427  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1428 
1429  const PermutationVector& mapping = m_Parameters.m_DimMappings;
1430 
1431  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1432  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1433 
1434  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
1435  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
1436 
1437  for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
1438  {
1439  if (inputTensorInfo.GetShape()[i] != outputTensorInfo.GetShape()[mapping[i]])
1440  {
1441  throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(i) +
1442  " (=" + to_string(inputTensorInfo.GetShape()[i]) + ") " +
1443  "must match dst dimension " + to_string(mapping[i]) +
1444  " (=" + to_string(outputTensorInfo.GetShape()[mapping[i]]) + ")");
1445  }
1446  }
1447 
1448  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1449 }
1450 
1451 void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1452 {
1453  const std::string descriptorName{"Pooling2dQueueDescriptor"};
1454 
1455  ValidateNumInputs(workloadInfo, descriptorName, 1);
1456  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1457 
1458  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1459  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1460 
1461  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1462  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1463 
1464  std::vector<DataType> supportedTypes =
1465  {
1472  };
1473 
1474  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1475  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1476 }
1477 
1479 {
1480  const std::string descriptorName{"ResizeBilinearQueueDescriptor"};
1481 
1482  ValidateNumInputs(workloadInfo, descriptorName, 1);
1483  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1484 
1485  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1486  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1487 
1488  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1489  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1490 
1491  std::vector<DataType> supportedTypes =
1492  {
1499  };
1500 
1501  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1502  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1503 
1504  // ResizeBilinear only changes width and height: batch and channel count must match.
1505  const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0];
1506  const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0];
1507  if (inputBatchSize != outputBatchSize)
1508  {
1510  fmt::format("{}: Input batch size ({}) does not match output batch size ({})",
1511  descriptorName, inputBatchSize, outputBatchSize));
1512  }
1513 
1514  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1515  const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1516  const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1517  if (inputChannelCount != outputChannelCount)
1518  {
1520  fmt::format("{}: Input channel count ({}) does not match output channel count ({})",
1521  descriptorName, inputChannelCount, outputChannelCount));
1522  }
1523 }
1524 
1525 void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1526 {
1527  const std::string descriptorName{"ResizeQueueDescriptor"};
1528 
1529  ValidateNumInputs(workloadInfo, descriptorName, 1);
1530  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1531 
1532  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1533  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1534 
1535  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1536  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1537 
1538  std::vector<DataType> supportedTypes =
1539  {
1546  };
1547 
1548  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1549  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1550 
1551  // Resize only changes width and height: batch and channel count must match.
1552  const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0];
1553  const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0];
1554  if (inputBatchSize != outputBatchSize)
1555  {
1557  fmt::format("{}: Input batch size ({}) does not match output batch size ({})",
1558  descriptorName, inputBatchSize, outputBatchSize));
1559  }
1560 
1561  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1562  const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1563  const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1564  if (inputChannelCount != outputChannelCount)
1565  {
1567  fmt::format("{}: Input channel count ({}) does not match output channel count ({})",
1568  descriptorName, inputChannelCount, outputChannelCount));
1569  }
1570 }
1571 
1573 {
1574  const std::string descriptorName{"FakeQuantizationQueueDescriptor"};
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, 2, "input");
1583  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1584 
1585  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1586 
1587  if (m_Parameters.m_Min > m_Parameters.m_Max)
1588  {
1589  throw InvalidArgumentException(descriptorName + ": min cannot be greater than max");
1590  }
1591 }
1592 
1594 {
1595  const std::string descriptorName{"InstanceNormalizationQueueDescriptor"};
1596 
1597  ValidateNumInputs(workloadInfo, descriptorName, 1);
1598  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1599 
1600  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1601  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1602 
1603  if (inputTensorInfo.GetNumDimensions() > 4)
1604  {
1605  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1606  }
1607 
1608  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1609 
1610  // Check the supported data types
1611  std::vector<DataType> supportedTypes =
1612  {
1616  };
1617 
1618  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1619  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1620 }
1621 
1623 {
1624  const std::string descriptorName{"L2NormalizationQueueDescriptor"};
1625 
1626  ValidateNumInputs(workloadInfo, descriptorName, 1);
1627  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1628 
1629  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1630  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1631 
1632  if (inputTensorInfo.GetNumDimensions() > 4)
1633  {
1634  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1635  }
1636 
1637  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1638 
1639  // Check the supported data types
1640  std::vector<DataType> supportedTypes =
1641  {
1648  };
1649 
1650  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1651  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1652 }
1653 
1654 void LogSoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1655 {
1656  const std::string descriptorName{"LogSoftmaxQueueDescriptor"};
1657 
1658  ValidateNumInputs(workloadInfo, descriptorName, 1);
1659  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1660 
1661  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1662  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1663 
1664  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1665 
1666  std::vector<DataType> supportedTypes =
1667  {
1671  };
1672 
1673  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1674  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1675 }
1676 
1677 void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1678 {
1679  const std::string descriptorName{"ConstantQueueDescriptor"};
1680 
1681  ValidateNumInputs(workloadInfo, descriptorName, 0);
1682  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1683 
1684  if (!m_LayerOutput)
1685  {
1686  throw InvalidArgumentException(descriptorName + ": No const input specified.");
1687  }
1688 
1689  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1690  ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(), outputTensorInfo, descriptorName, "constant", "output");
1691 
1692  // Check the supported data types
1693  std::vector<DataType> supportedTypes =
1694  {
1703  };
1704 
1705  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1706 }
1707 
1708 void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1709 {
1710  const std::string descriptorName{"ReshapeQueueDescriptor"};
1711 
1712  ValidateNumInputs(workloadInfo, descriptorName, 1);
1713  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1714 
1715  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1716  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1717 
1718  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1719 
1720  // Check the supported data types
1721  std::vector<DataType> supportedTypes =
1722  {
1731  };
1732 
1733  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1734  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1735 }
1736 
1738 {
1739  const std::string descriptorName{"SpaceToBatchNdQueueDescriptor"};
1740 
1741  ValidateNumInputs(workloadInfo, descriptorName, 1);
1742  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1743 
1744  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1745  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1746 
1747  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1748  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1749 
1750  if (m_Parameters.m_BlockShape.size() != 2)
1751  {
1752  throw InvalidArgumentException(descriptorName + ": Block Shape must contain 2 spatial dimensions.");
1753  }
1754 
1755  if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
1756  {
1757  throw InvalidArgumentException(descriptorName + ": Pad List must contain the same number of "
1758  "dimensions as Block Shape.");
1759  }
1760 
1761  const TensorShape& inputShape = inputTensorInfo.GetShape();
1762 
1763  std::pair<unsigned int, unsigned int> heightPad = m_Parameters.m_PadList[0];
1764  std::pair<unsigned int, unsigned int> widthPad = m_Parameters.m_PadList[1];
1765 
1766  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1767 
1768  const unsigned int inputWidth = inputShape[dimensionIndices.GetWidthIndex()] +
1769  widthPad.first + widthPad.second;
1770  const unsigned int inputHeight = inputShape[dimensionIndices.GetHeightIndex()] +
1771  heightPad.first + heightPad.second;
1772 
1773  const unsigned int numInputElements = inputShape[0] * inputHeight * inputWidth *
1774  inputShape[dimensionIndices.GetChannelsIndex()];
1775  const unsigned int numOutputElements = outputTensorInfo.GetNumElements();
1776 
1777  if (numOutputElements != numInputElements)
1778  {
1779  throw InvalidArgumentException(descriptorName + ": Input tensor has " +
1780  to_string(numInputElements) + " after padding but output tensor has " +
1781  to_string(numOutputElements) + " elements.");
1782  }
1783 
1784  if (inputHeight % m_Parameters.m_BlockShape[0] != 0 || inputWidth % m_Parameters.m_BlockShape[1] != 0)
1785  {
1786  throw InvalidArgumentException(descriptorName + ": Input shape after padding must be "
1787  "divisible by Block Shape in all spatial dimensions");
1788  }
1789 
1790  std::vector<DataType> supportedTypes =
1791  {
1798  };
1799 
1800  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1801  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1802 }
1803 
1805 {
1806  const std::string descriptorName{"SpaceToDepthQueueDescriptor"};
1807 
1808  ValidateNumInputs(workloadInfo, descriptorName, 1);
1809  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1810 
1811  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1812  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1813 
1814  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1815  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1816 
1817  std::vector<DataType> supportedTypes =
1818  {
1825  };
1826 
1827  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1828  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1829 
1830  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1831 
1832  if (m_Parameters.m_BlockSize == 0)
1833  {
1834  throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
1835  }
1836 
1837  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1838  const unsigned int wIndex = dimensionIndices.GetWidthIndex();
1839  const unsigned int hIndex = dimensionIndices.GetHeightIndex();
1840  const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
1841 
1842  const TensorShape& inputShape = inputTensorInfo.GetShape();
1843  if (inputShape[hIndex] % m_Parameters.m_BlockSize != 0 || inputShape[wIndex] % m_Parameters.m_BlockSize != 0)
1844  {
1845  throw InvalidArgumentException(descriptorName + ": Input shape must be divisible "
1846  "by block size in all spatial dimensions");
1847  }
1848 
1849  const TensorShape& outputShape = outputTensorInfo.GetShape();
1850  if (outputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
1851  {
1852  throw InvalidArgumentException(descriptorName + ": The depth of the output tensor"
1853  "must be divisible by the square of block size." );
1854  }
1855 }
1856 
1857 void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1858 {
1859  const std::string descriptorName{"FloorQueueDescriptor"};
1860 
1861  ValidateNumInputs(workloadInfo, descriptorName, 1);
1862  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1863 
1864  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1865  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1866 
1867  std::vector<DataType> supportedTypes =
1868  {
1873  };
1874 
1875  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1876  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1877  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1878  ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1879 }
1880 
1881 void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1882 {
1883  // ported from android/ml/nn/common/operations/LSTM.cpp CheckInputTensorDimensions()
1884 
1885  const std::string descriptorName{"LstmQueueDescriptor"};
1886 
1887  // check dimensions of all inputs and outputs
1888  if (workloadInfo.m_InputTensorInfos.size() != 3)
1889  {
1890  throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
1891  }
1892  if (workloadInfo.m_OutputTensorInfos.size() != 4)
1893  {
1894  throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
1895  }
1896 
1897  std::vector<DataType> supportedTypes =
1898  {
1903  };
1904 
1905  // check for supported type of one input and match them with all the other input and output
1906  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
1907 
1908  // type matches all other inputs
1909  for (uint32_t i = 1u; i < workloadInfo.m_InputTensorInfos.size(); ++i)
1910  {
1911  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1912  workloadInfo.m_InputTensorInfos[i],
1913  descriptorName,
1914  "input_0",
1915  "input_" + std::to_string(i));
1916  }
1917  // type matches all other outputs
1918  for (uint32_t i = 0u; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
1919  {
1920  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1921  workloadInfo.m_OutputTensorInfos[i],
1922  "LstmQueueDescriptor",
1923  "input_0",
1924  "output_" + std::to_string(i));
1925  }
1926 
1927  // Making sure clipping parameters have valid values.
1928  // == 0 means no clipping
1929  // > 0 means clipping
1930  if (m_Parameters.m_ClippingThresCell < 0.0f)
1931  {
1932  throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
1933  }
1934  if (m_Parameters.m_ClippingThresProj < 0.0f)
1935  {
1936  throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
1937  }
1938 
1939  // Inferring batch size, number of outputs and number of cells from the inputs.
1940  const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[1];
1941  const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
1942  ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
1943  const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
1944  ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
1945  const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
1946 
1947  // input tensor
1948  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 2, (n_batch * n_input),
1949  descriptorName + " input_0");
1950  // outputStateInTensor
1951  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
1952  descriptorName + " input_1");
1953  // outputStateInTensor
1954  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
1955  descriptorName + " input_2");
1956  // scratchBufferTensor
1957  unsigned int scratchBufferSize = m_Parameters.m_CifgEnabled ? n_cell * 3 : n_cell * 4;
1958  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[0], 2, (n_batch * scratchBufferSize),
1959  descriptorName + " output_0");
1960  // outputStateOutTensor
1961  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[1], 2, (n_batch * n_output),
1962  descriptorName + " output_1");
1963  // cellStateOutTensor
1964  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 2, (n_batch * n_cell),
1965  descriptorName + " output_2");
1966  // outputTensor
1967  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[3], 2, (n_batch * n_output),
1968  descriptorName + " output_3");
1969 
1970  // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
1971  if ( m_InputToInputWeights )
1972  {
1973  ValidateTensorNumDimNumElem(m_InputToInputWeights->GetTensorInfo(), 2,
1974  (n_cell * n_input), "InputLayerNormWeights");
1975  }
1976 
1977  ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
1978  ValidateTensorNumDimNumElem(m_InputToForgetWeights->GetTensorInfo(), 2,
1979  (n_cell * n_input), "InputToForgetWeights");
1980 
1981  ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
1982  ValidateTensorNumDimNumElem(m_InputToCellWeights->GetTensorInfo(), 2,
1983  (n_cell * n_input), "InputToCellWeights");
1984 
1985  if ( m_RecurrentToInputWeights )
1986  {
1987  ValidateTensorNumDimNumElem(m_RecurrentToInputWeights->GetTensorInfo(), 2,
1988  (n_cell * n_output), "RecurrentToInputWeights");
1989  }
1990 
1991  ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
1992  ValidateTensorNumDimNumElem(m_RecurrentToForgetWeights->GetTensorInfo(), 2,
1993  (n_cell * n_output), "RecurrentToForgetWeights");
1994 
1995  ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
1996  ValidateTensorNumDimNumElem(m_RecurrentToCellWeights->GetTensorInfo(), 2,
1997  (n_cell * n_output), "RecurrentToCellWeights");
1998 
1999  // Make sure the input-gate's parameters are either both present (regular
2000  // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
2001  bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
2002  !m_Parameters.m_CifgEnabled) ||
2003  (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
2004  m_Parameters.m_CifgEnabled));
2005  if (!cifg_weights_all_or_none)
2006  {
2007  throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
2008  "RecurrentToInputWeights must either both be present (regular LSTM) "
2009  "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
2010  "accordingly.");
2011  }
2012 
2013  if ( m_CellToInputWeights )
2014  {
2015  ValidateTensorNumDimNumElem(m_CellToInputWeights->GetTensorInfo(), 1,
2016  n_cell, "CellToInputWeights");
2017  }
2018  if ( m_CellToForgetWeights )
2019  {
2020  ValidateTensorNumDimNumElem(m_CellToForgetWeights->GetTensorInfo(), 1,
2021  n_cell, "CellToForgetWeights");
2022  }
2023  if ( m_CellToOutputWeights )
2024  {
2025  ValidateTensorNumDimNumElem(m_CellToOutputWeights->GetTensorInfo(), 1,
2026  n_cell, "CellToOutputWeights");
2027  }
2028 
2029  // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
2030  bool peephole_weights_all_or_none =
2031  (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
2032  && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
2033  || ( !m_CellToInputWeights && !m_CellToForgetWeights
2034  && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
2035  if (!peephole_weights_all_or_none)
2036  {
2037  throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
2038  }
2039 
2040  // Make sure the input gate bias is present only when not a CIFG-LSTM.
2041  if (m_Parameters.m_CifgEnabled)
2042  {
2043  if (m_InputGateBias)
2044  {
2045  throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
2046  }
2047  }
2048  else
2049  {
2050  if (!m_InputGateBias)
2051  {
2052  throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
2053  "must be present.");
2054  }
2055  ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1,
2056  n_cell, "InputGateBias");
2057  }
2058 
2059  ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
2060  ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
2061 
2062  ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
2063  ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
2064 
2065  ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
2066  ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
2067 
2068  if (m_ProjectionWeights)
2069  {
2070  ValidateTensorNumDimNumElem(m_ProjectionWeights->GetTensorInfo(), 2,
2071  (n_cell * n_output), "ProjectionWeights");
2072  }
2073  if (m_ProjectionBias)
2074  {
2075  ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
2076  }
2077 
2078  // Making sure the projection tensors are consistent:
2079  // 1) If projection weight is not present, then projection bias should not be
2080  // present.
2081  // 2) If projection weight is present, then projection bias is optional.
2082  bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
2083  !m_Parameters.m_ProjectionEnabled)
2084  || (m_ProjectionWeights && !m_ProjectionBias &&
2085  m_Parameters.m_ProjectionEnabled)
2086  || (m_ProjectionWeights && m_ProjectionBias &&
2087  m_Parameters.m_ProjectionEnabled));
2088  if (!projecton_tensors_consistent)
2089  {
2090  throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
2091  }
2092 
2093  // The four layer normalization weights either all have values or none of them have values. Additionally, if
2094  // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
2095  // either all have values or none of them have values. Layer normalization is used when the values of all the
2096  // layer normalization weights are present
2097  if (m_InputLayerNormWeights)
2098  {
2099  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
2100  }
2101  if (m_ForgetLayerNormWeights)
2102  {
2103  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2104  }
2105  if (m_CellLayerNormWeights)
2106  {
2107  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2108  }
2109  if (m_OutputLayerNormWeights)
2110  {
2111  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2112  }
2113 
2114  if (m_Parameters.m_LayerNormEnabled)
2115  {
2116  if (!m_Parameters.m_CifgEnabled)
2117  {
2118  if (!m_InputLayerNormWeights)
2119  {
2120  throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
2121  "disabled but InputLayerNormWeights are not present");
2122  }
2123  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(),
2124  1, n_cell, "InputLayerNormWeights");
2125  }
2126  else if (m_InputLayerNormWeights)
2127  {
2128  throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
2129  "enabled");
2130  }
2131 
2132  ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
2133  "ForgetLayerNormWeights");
2134  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2135 
2136  ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
2137  "OutputLayerNormWeights");
2138  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2139 
2140  ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
2141  "CellLayerNormWeights");
2142  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2143  }
2144  else if (m_InputLayerNormWeights || m_ForgetLayerNormWeights || m_OutputLayerNormWeights || m_CellLayerNormWeights)
2145  {
2146  throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
2147  "normalisation weights are present.");
2148  }
2149 }
2150 
2152 {
2153  const std::string descriptorName{"ConvertBf16ToFp32QueueDescriptor"};
2154 
2155  ValidateNumInputs(workloadInfo, descriptorName, 1);
2156  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2157 
2158  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2159  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2160 
2161  if (inputTensorInfo.GetDataType() != DataType::BFloat16)
2162  {
2163  throw InvalidArgumentException(descriptorName + ": Input tensor type must be BFloat16.");
2164  }
2165 
2166  if (outputTensorInfo.GetDataType() != DataType::Float32)
2167  {
2168  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32.");
2169  }
2170 
2171  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2172 }
2173 
2175 {
2176  const std::string descriptorName{"ConvertFp32ToBf16QueueDescriptor"};
2177 
2178  ValidateNumInputs(workloadInfo, descriptorName, 1);
2179  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2180 
2181  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2182  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2183 
2184  if (inputTensorInfo.GetDataType() != DataType::Float32)
2185  {
2186  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32.");
2187  }
2188 
2189  if (outputTensorInfo.GetDataType() != DataType::BFloat16)
2190  {
2191  throw InvalidArgumentException(descriptorName + ": Output tensor type must be BFloat16.");
2192  }
2193 
2194  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2195 }
2196 
2198 {
2199  const std::string descriptorName{"ConvertFp32ToFp16QueueDescriptor"};
2200 
2201  ValidateNumInputs(workloadInfo, descriptorName, 1);
2202  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2203 
2204  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2205  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2206 
2207  if (inputTensorInfo.GetDataType() != DataType::Float32)
2208  {
2209  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32.");
2210  }
2211 
2212  if (outputTensorInfo.GetDataType() != DataType::Float16)
2213  {
2214  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float16.");
2215  }
2216 
2217  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2218 }
2219 
2221 {
2222  const std::string descriptorName{"ConvertFp16ToFp32QueueDescriptor"};
2223 
2224  ValidateNumInputs(workloadInfo, descriptorName, 1);
2225  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2226 
2227  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2228  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2229 
2230  if (inputTensorInfo.GetDataType() != DataType::Float16)
2231  {
2232  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float16.");
2233  }
2234 
2235  if (outputTensorInfo.GetDataType() != DataType::Float32)
2236  {
2237  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32.");
2238  }
2239 
2240  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2241 }
2242 
2243 void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2244 {
2245  const std::string descriptorName{"DivisionQueueDescriptor"};
2246 
2247  ValidateNumInputs(workloadInfo, descriptorName, 2);
2248  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2249 
2250  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2251  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2252  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2253 
2254  std::vector<DataType> supportedTypes =
2255  {
2263  };
2264 
2265  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2266  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2267  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2268 
2269  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2270  inputTensorInfo1,
2271  outputTensorInfo,
2272  descriptorName,
2273  "input_0",
2274  "input_1");
2275 }
2276 
2278 {
2279  const std::string descriptorName{"SubtractionQueueDescriptor"};
2280 
2281  ValidateNumInputs(workloadInfo, descriptorName, 2);
2282  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2283 
2284  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2285  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2286  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2287 
2288  std::vector<DataType> supportedTypes =
2289  {
2297  };
2298 
2299  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2300  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2301  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2302 
2303  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2304  inputTensorInfo1,
2305  outputTensorInfo,
2306  descriptorName,
2307  "input_0",
2308  "input_1");
2309 }
2310 
2311 void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2312 {
2313  const std::string descriptorName{"MaximumQueueDescriptor"};
2314 
2315  ValidateNumInputs(workloadInfo, descriptorName, 2);
2316  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2317 
2318  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2319  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2320  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2321 
2322  std::vector<DataType> supportedTypes =
2323  {
2331  };
2332 
2333  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2334  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2335  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2336 
2337  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2338  inputTensorInfo1,
2339  outputTensorInfo,
2340  descriptorName,
2341  "input_0",
2342  "input_1");
2343 }
2344 
2345 void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2346 {
2347  const std::string descriptorName{"MeanQueueDescriptor"};
2348 
2349  ValidateNumInputs(workloadInfo, descriptorName, 1);
2350  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2351 
2352  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2353  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2354 
2355  std::vector<DataType> supportedTypes =
2356  {
2363  };
2364 
2365  // First check if input tensor data type is supported, then
2366  // check if this data type matches the output tensor data type
2367  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2368  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2369 
2370  if (m_Parameters.m_KeepDims)
2371  {
2372  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2373  }
2374  else if (m_Parameters.m_Axis.empty())
2375  {
2376  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
2377  }
2378  else
2379  {
2380  unsigned int outputDim =
2381  inputTensorInfo.GetNumDimensions() - armnn::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
2382  ValidateTensorNumDimensions(outputTensorInfo,
2383  descriptorName,
2384  outputDim > 0 ? outputDim : 1,
2385  "output");
2386  }
2387 }
2388 
2389 void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2390 {
2391  const std::string descriptorName{"PadQueueDescriptor"};
2392 
2393  ValidateNumInputs(workloadInfo, descriptorName, 1);
2394  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2395 
2396  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2397  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2398 
2399  // input and output should have the same number of dimensions
2400  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2401 
2402  // there should be entry in the pad list for each dimension in the input tensor
2403  if (m_Parameters.m_PadList.size() != inputTensorInfo.GetNumDimensions()) {
2404  throw InvalidArgumentException(descriptorName + ":Pad List should contain the same number of entries "
2405  "as there are dimensions in the input tensor that is " +
2406  std::to_string(inputTensorInfo.GetNumDimensions()) + " entries " +
2407  " not " + std::to_string(m_Parameters.m_PadList.size()) + " entries.");
2408  }
2409 }
2410 
2411 void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2412 {
2413  const std::string descriptorName{"QuantizeQueueDescriptor"};
2414 
2415  ValidateNumInputs(workloadInfo, descriptorName, 1);
2416  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2417 
2418  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2419  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2420 
2421  std::vector<DataType> supportedTypes =
2422  {
2430  };
2431 
2432  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2433 
2434  if (!IsQuantizedType(outputTensorInfo.GetDataType()))
2435  {
2436  throw InvalidArgumentException(descriptorName + ": Output of quantized layer must be quantized type.");
2437  }
2438 }
2439 
2441 {
2442  const std::string descriptorName{"BatchToSpaceNdQueueDescriptor"};
2443 
2444  ValidateNumInputs(workloadInfo, descriptorName, 1);
2445  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2446 
2447  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2448  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2449 
2450  std::vector<DataType> supportedTypes =
2451  {
2458  };
2459 
2460  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2461  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2462 }
2463 
2465 {
2466  const std::string descriptorName{"StridedSliceQueueDescriptor"};
2467 
2468  ValidateNumInputs(workloadInfo, descriptorName, 1);
2469  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2470 
2471  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2472  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2473 
2474  std::vector<DataType> supportedTypes =
2475  {
2482  };
2483 
2484  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2485  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2486 
2487  ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2488 
2489  const uint32_t rank = inputTensorInfo.GetNumDimensions();
2490  if (rank > 4)
2491  {
2492  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
2493  }
2494 
2495  // Begin, End & Stride length must be of rank(input0)
2496  if (m_Parameters.m_Begin.size() != rank)
2497  {
2498  throw InvalidArgumentException(descriptorName + ": Begin length must be of rank " + std::to_string(rank));
2499  }
2500 
2501  if (m_Parameters.m_End.size() != rank)
2502  {
2503  throw InvalidArgumentException(descriptorName + ": End length must be of rank " + std::to_string(rank));
2504  }
2505 
2506  if (m_Parameters.m_Stride.size() != rank)
2507  {
2508  throw InvalidArgumentException(descriptorName + ": Stride length must be of rank " + std::to_string(rank));
2509  }
2510 
2511  // Stride entries must be non-zero
2512  for (auto& stride : m_Parameters.m_Stride)
2513  {
2514  if (stride == 0)
2515  {
2516  throw InvalidArgumentException(descriptorName + ": Stride entries must be non-zero.");
2517  }
2518  }
2519 }
2520 
2521 void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2522 {
2523  const std::string descriptorName{"MinimumQueueDescriptor"};
2524 
2525  ValidateNumInputs(workloadInfo, descriptorName, 2);
2526  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2527 
2528  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2529  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2530  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2531 
2532  std::vector<DataType> supportedTypes =
2533  {
2541  };
2542 
2543  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2544  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2545  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2546 
2547  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2548  inputTensorInfo1,
2549  outputTensorInfo,
2550  descriptorName,
2551  "input_0",
2552  "input_1");
2553 }
2554 
2555 void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2556 {
2557  const std::string descriptorName{"DebugQueueDescriptor"};
2558 
2559  ValidateNumInputs(workloadInfo, descriptorName, 1);
2560  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2561 }
2562 
2563 void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2564 {
2565  const std::string descriptorName{"EqualQueueDescriptor"};
2566 
2567  ValidateNumInputs(workloadInfo, descriptorName, 2);
2568  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2569 
2570  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2571  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2572  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2573 
2574  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2575  inputTensorInfo1,
2576  outputTensorInfo,
2577  descriptorName,
2578  "input_0",
2579  "input_1");
2580 
2581  if (outputTensorInfo.GetDataType() != DataType::Boolean)
2582  {
2583  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2584  }
2585 }
2586 
2587 void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2588 {
2589  const std::string descriptorName{"GreaterQueueDescriptor"};
2590 
2591  ValidateNumInputs(workloadInfo, descriptorName, 2);
2592  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2593 
2594  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2595  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2596  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2597 
2598  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2599  inputTensorInfo1,
2600  outputTensorInfo,
2601  descriptorName,
2602  "input_0",
2603  "input_1");
2604 
2605  if (outputTensorInfo.GetDataType() != DataType::Boolean)
2606  {
2607  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2608  }
2609 }
2610 
2611 void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2612 {
2613  const std::string descriptorName{"RsqrtQueueDescriptor"};
2614 
2615  ValidateNumInputs(workloadInfo, descriptorName, 1);
2616  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2617 
2618  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2619  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2620 
2621  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2622 
2623  std::vector<DataType> supportedTypes =
2624  {
2631  };
2632 
2633  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2634  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2635 }
2636 
2637 void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2638 {
2639  const std::string descriptorName{"GatherQueueDescriptor"};
2640 
2641  ValidateNumInputs(workloadInfo, descriptorName, 2);
2642  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2643 
2644  const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1];
2645  if (indicesTensorInfo.GetDataType() != DataType::Signed32)
2646  {
2647  throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32.");
2648  }
2649 
2650  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2651  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2652 
2653  std::vector<DataType> supportedTypes =
2654  {
2662  };
2663 
2664  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2665 
2666  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2667 
2668  unsigned int outputDim = inputTensorInfo.GetNumDimensions() + indicesTensorInfo.GetNumDimensions() - 1;
2669  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output");
2670 }
2671 
2673 {
2674  const std::string& descriptorName{"DetectionPostProcessQueueDescriptor"};
2675 
2676  ValidateNumInputs(workloadInfo, descriptorName, 2);
2677 
2678  if (workloadInfo.m_OutputTensorInfos.size() != 4)
2679  {
2680  throw InvalidArgumentException(descriptorName + ": Requires exactly four outputs. " +
2681  to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
2682  }
2683 
2684  if (m_Anchors == nullptr)
2685  {
2686  throw InvalidArgumentException(descriptorName + ": Anchors tensor descriptor is missing.");
2687  }
2688 
2689  const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
2690  const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
2691  const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
2692 
2693  const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
2694  const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
2695  const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
2696  const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
2697 
2698  ValidateTensorNumDimensions(boxEncodingsInfo, descriptorName, 3, "box encodings");
2699  ValidateTensorNumDimensions(scoresInfo, descriptorName, 3, "scores");
2700  ValidateTensorNumDimensions(anchorsInfo, descriptorName, 2, "anchors");
2701 
2702  const std::vector<DataType> supportedInputTypes =
2703  {
2710  };
2711 
2712  ValidateDataTypes(boxEncodingsInfo, supportedInputTypes, descriptorName);
2713  ValidateDataTypes(scoresInfo, supportedInputTypes, descriptorName);
2714  ValidateDataTypes(anchorsInfo, supportedInputTypes, descriptorName);
2715 
2716  ValidateTensorNumDimensions(detectionBoxesInfo, descriptorName, 3, "detection boxes");
2717  ValidateTensorNumDimensions(detectionScoresInfo, descriptorName, 2, "detection scores");
2718  ValidateTensorNumDimensions(detectionClassesInfo, descriptorName, 2, "detection classes");
2719  ValidateTensorNumDimensions(numDetectionsInfo, descriptorName, 1, "num detections");
2720 
2721  // NOTE: Output is always Float32 regardless of input type
2722  ValidateTensorDataType(detectionBoxesInfo, DataType::Float32, descriptorName, "detection boxes");
2723  ValidateTensorDataType(detectionScoresInfo, DataType::Float32, descriptorName, "detection scores");
2724  ValidateTensorDataType(detectionClassesInfo, DataType::Float32, descriptorName, "detection classes");
2725  ValidateTensorDataType(numDetectionsInfo, DataType::Float32, descriptorName, "num detections");
2726 
2727  if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f)
2728  {
2729  throw InvalidArgumentException(descriptorName + ": Intersection over union threshold "
2730  "must be positive and less than or equal to 1.");
2731  }
2732 
2733  if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
2734  {
2735  throw InvalidArgumentException(descriptorName + ": Number of classes with background "
2736  "should be equal to number of classes + 1.");
2737  }
2738 }
2739 
2740 void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2741 {
2742  const std::string& descriptorName{"DequantizeQueueDescriptor"};
2743 
2744  ValidateNumInputs(workloadInfo, descriptorName, 1);
2745  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2746 
2747  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2748  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2749 
2750  if (!IsQuantizedType(inputTensorInfo.GetDataType()))
2751  {
2752  throw InvalidArgumentException(descriptorName + ": Input to dequantize layer must be quantized type.");
2753  }
2754 
2755  std::vector<DataType> supportedTypes =
2756  {
2760  };
2761 
2762  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2763 }
2764 
2765 void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2766 {
2767  const std::string& descriptorName{"MergeQueueDescriptor"};
2768 
2769  ValidateNumInputs(workloadInfo, descriptorName, 2);
2770  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2771 
2772  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2773  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2774  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2775 
2776  ValidateTensorShapesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2777  ValidateTensorShapesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2778 
2779  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2780  ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2781 }
2782 
2783 void ShapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2784 {
2785  const std::string& descriptorName{"ShapeQueueDescriptor"};
2786 
2787  ValidateNumInputs(workloadInfo, descriptorName, 1);
2788  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2789 
2790  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2791  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2792 
2793  std::vector<DataType> supportedTypes =
2794  {
2804  };
2805 
2806  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2807  ValidateDataTypes(outputTensorInfo, {DataType::Signed32}, descriptorName);
2808 }
2809 
2810 void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2811 {
2812  const std::string& descriptorName{"SwitchQueueDescriptor"};
2813 
2814  ValidateNumInputs(workloadInfo, descriptorName, 2);
2815  ValidateNumOutputs(workloadInfo, descriptorName, 2);
2816 
2817  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2818  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2819 
2820  const TensorInfo& outputTensorInfo0 = workloadInfo.m_OutputTensorInfos[0];
2821  const TensorInfo& outputTensorInfo1 = workloadInfo.m_OutputTensorInfos[1];
2822 
2823  std::vector<DataType> supportedTypes =
2824  {
2830  };
2831 
2832  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2833  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2834 
2835  ValidateDataTypes(outputTensorInfo0, supportedTypes, descriptorName);
2836  ValidateDataTypes(outputTensorInfo1, supportedTypes, descriptorName);
2837 
2838  ValidateTensorShapesMatch(inputTensorInfo0,
2839  outputTensorInfo0,
2840  descriptorName,
2841  "input_0",
2842  "output_0");
2843 
2844  ValidateTensorShapesMatch(inputTensorInfo0,
2845  outputTensorInfo1,
2846  descriptorName,
2847  "input_0",
2848  "output_1");
2849 }
2850 
2851 void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& /*workloadInfo*/) const
2852 {
2853  // This is internally generated so it should not need validation.
2854 }
2855 
2856 void PreluQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2857 {
2858  const std::string& descriptorName{"PreluQueueDescriptor"};
2859 
2860  ValidateNumInputs(workloadInfo, descriptorName, 2);
2861  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2862 
2863  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2864  const TensorInfo& alphaTensorInfo = workloadInfo.m_InputTensorInfos[1];
2865  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2866 
2867  std::vector<DataType> supportedTypes
2868  {
2875  };
2876 
2877  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2878  ValidateDataTypes(alphaTensorInfo, supportedTypes, descriptorName);
2879 
2880  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2881 
2882  ValidateTensorDataTypesMatch(inputTensorInfo, alphaTensorInfo, descriptorName, "input", "alpha");
2883  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "ouptut");
2884 
2885  ValidateBroadcastTensorShapesMatch(inputTensorInfo,
2886  alphaTensorInfo,
2887  outputTensorInfo,
2888  descriptorName,
2889  "input",
2890  "alpha");
2891 }
2892 
2894 {
2895  const std::string descriptorName{"TransposeConvolution2dQueueDescriptor"};
2896 
2897  ValidateNumInputs(workloadInfo, descriptorName, 1);
2898  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2899 
2900  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2901  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2902 
2903  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
2904  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
2905 
2906  ValidatePointer(m_Weight, descriptorName, "weight");
2907 
2908  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
2909  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
2910 
2911  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
2912 
2913  Optional<TensorInfo> optionalBiasTensorInfo;
2914  if (m_Parameters.m_BiasEnabled)
2915  {
2916  ValidatePointer(m_Bias, descriptorName, "bias");
2917 
2918  optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
2919  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
2920 
2921  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
2922  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
2923  }
2924 
2925  ValidatePerAxisQuantization(inputTensorInfo,
2926  outputTensorInfo,
2927  weightTensorInfo,
2928  optionalBiasTensorInfo,
2929  descriptorName);
2930 
2931  std::vector<DataType> supportedTypes =
2932  {
2939  };
2940 
2941  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2942  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2943 }
2944 
2945 void TransposeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2946 {
2947  const std::string descriptorName{"TransposeQueueDescriptor"};
2948 
2949  ValidateNumInputs(workloadInfo, descriptorName, 1);
2950  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2951 
2952  const PermutationVector& mapping = m_Parameters.m_DimMappings;
2953 
2954  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2955  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2956 
2957  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
2958  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
2959 
2960  for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
2961  {
2962  if (inputTensorInfo.GetShape()[mapping[i]] != outputTensorInfo.GetShape()[i])
2963  {
2964  throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(mapping[i]) +
2965  " (=" + to_string(inputTensorInfo.GetShape()[mapping[i]]) + ") " +
2966  "must match dst dimension " + to_string(i) +
2967  " (=" + to_string(outputTensorInfo.GetShape()[i]) + ")");
2968  }
2969  }
2970 
2971  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2972 }
2973 
2974 void QLstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2975 {
2976  const std::string descriptorName{"QLstmQueueDescriptor"};
2977 
2978  // Validate number of inputs/outputs
2979  ValidateNumInputs(workloadInfo, descriptorName, 3);
2980  ValidateNumOutputs(workloadInfo, descriptorName, 3);
2981 
2982  // Input/output tensor info
2983  auto inputInfo = workloadInfo.m_InputTensorInfos[0];
2984  auto outputStateInInfo = workloadInfo.m_InputTensorInfos[1];
2985  auto cellStateInInfo = workloadInfo.m_InputTensorInfos[2];
2986 
2987  auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
2988  auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
2989  auto outputInfo = workloadInfo.m_OutputTensorInfos[2];
2990 
2991  // Supported types for various tensors in QLSTM
2992  std::vector<DataType> inputOutputSupportedTypes =
2993  {
2995  };
2996 
2997  std::vector<DataType> cellStateSupportedTypes =
2998  {
3000  };
3001 
3002  std::vector<DataType> weightsSupportedTypes =
3003  {
3005  };
3006 
3007  std::vector<DataType> layerNormPeepholeWeightsSupportedTypes =
3008  {
3010  };
3011 
3012  std::vector<DataType> biasSupportedTypes =
3013  {
3015  };
3016 
3017  // Validate types of input/output tensors
3018  ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3019  ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3020  ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3021 
3022  ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3023  ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3024  ValidateDataTypes(outputInfo, inputOutputSupportedTypes, descriptorName);
3025 
3026  // Validate matching types of input/output tensors
3027  ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3028  ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3029  "outputStateIn", "outputStateOut");
3030  ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3031 
3032  // Infer number of batches, number of units, input size and output size from tensor dimensions
3033  const uint32_t numBatches = inputInfo.GetShape()[0];
3034  const uint32_t inputSize = inputInfo.GetShape()[1];
3035  const uint32_t outputSize = outputStateInInfo.GetShape()[1];
3036  const uint32_t numUnits = cellStateInInfo.GetShape()[1];
3037 
3038  // Validate number of dimensions and number of elements for input/output tensors
3039  ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3040  ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3041  ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * numUnits), descriptorName + " cellStateIn");
3042 
3043  ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3044  ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * numUnits), descriptorName + " cellStateOut");
3045  ValidateTensorNumDimNumElem(outputInfo, 2, (numBatches * outputSize), descriptorName + " output");
3046 
3047  // Validate number of dimensions and number of elements for MANDATORY weight tensors
3048  ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3049  auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3050  ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (numUnits * inputSize), " InputToForgetWeights");
3051 
3052  ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3053  auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3054  ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (numUnits * inputSize), " InputToCellWeights");
3055 
3056  ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3057  auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3058  ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (numUnits * inputSize), " InputToOutputWeights");
3059 
3060  ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3061  auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3062  ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (numUnits * outputSize),
3063  " RecurrentToForgetWeights");
3064 
3065  ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3066  auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3067  ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3068 
3069  ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3070  auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3071  ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3072 
3073  // Validate data types for MANDATORY weights tensors (all should match each other)
3074  ValidateDataTypes(inputToForgetWeightsInfo, weightsSupportedTypes, descriptorName);
3075 
3076  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToCellWeightsInfo, descriptorName,
3077  "inputToForgetWeights", "inputToCellWeights");
3078  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3079  "inputToForgetWeights", "inputToOutputWeights");
3080 
3081  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3082  "inputToForgetWeights", "recurrentToForgeteights");
3083  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3084  "inputToForgetWeights", "recurrentToCellWeights");
3085  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3086  "inputToForgetWeights", "recurrentToOutputWeights");
3087 
3088  // Validate number of dimensions and number of elements for MANDATORY bias tensors
3089  ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3090  auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3091  ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, numUnits, " ForgetGateBias");
3092 
3093  ValidatePointer(m_CellBias, descriptorName, "CellBias");
3094  auto cellBiasInfo = m_CellBias->GetTensorInfo();
3095  ValidateTensorNumDimNumElem(cellBiasInfo, 1, numUnits, " CellBias");
3096 
3097  ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3098  auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3099  ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, numUnits, " OutputGateBias");
3100 
3101  // Validate data types for MANDATORY bias tensors
3102  ValidateDataTypes(forgetGateBiasInfo, biasSupportedTypes, descriptorName);
3103 
3104  ValidateTensorDataTypesMatch(forgetGateBiasInfo, cellBiasInfo, descriptorName,
3105  "forgetGateBias", "cellBias");
3106  ValidateTensorDataTypesMatch(forgetGateBiasInfo, outputGateBiasInfo, descriptorName,
3107  "forgetGateBias", "outputGateBias");
3108 
3109  // Validate OPTIONAL params: CIFG (inputToInputWeights, recurrentToInputWeights, inputGateBias)
3110  const bool allCifgParamsPresentOrNot = ((m_InputToInputWeights && m_RecurrentToInputWeights && m_InputGateBias &&
3111  !m_Parameters.m_CifgEnabled) ||
3112  (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
3113  !m_InputGateBias && m_Parameters.m_CifgEnabled));
3114 
3115  if (!allCifgParamsPresentOrNot)
3116  {
3117  throw InvalidArgumentException(descriptorName +
3118  ": InputToInputWeights, RecurrentToInputWeights and InputGateBias must either all be present "
3119  "(CIFG disabled) or not be present at all (CIFG enabled). m_Parameters.m_CifgEnabled should be "
3120  "set appropriately.");
3121  }
3122 
3123  if (!m_Parameters.m_CifgEnabled)
3124  {
3125  // Validate number of dimensions and number of elements
3126  auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3127  ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (numUnits * inputSize), " InputToInputWeights");
3128 
3129  auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3130  ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (numUnits * outputSize),
3131  " RecurrentToInputWeights");
3132 
3133  auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3134  ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, numUnits, " InputGateBias");
3135 
3136  // Validate data types
3137  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToInputWeightsInfo, descriptorName,
3138  "inputToForgetWeights", "inputToInputWeights");
3139  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3140  "inputToForgetWeights", "recurrentToInputWeights");
3141  ValidateTensorDataTypesMatch(forgetGateBiasInfo, inputGateBiasInfo, descriptorName,
3142  "forgetGateBias", "inputGateBias");
3143  }
3144 
3145  // Validate OPTIONAL params: Peephole (cellToInputWeights, cellToForgetWeights, cellToOutputWeights)
3146  bool allPeepholeWeightsPresentOrNot =
3147  (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
3148  && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
3149  || (!m_CellToInputWeights && !m_CellToForgetWeights
3150  && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
3151 
3152  if (!allPeepholeWeightsPresentOrNot)
3153  {
3154  throw InvalidArgumentException(descriptorName +
3155  ": CellToInputWeights, CellToForgetWeights and CellToOutputWeights should all be present (Peephole "
3156  "enabled) or not be present at all (Peephole disabled). CellToInputWeights should only be present "
3157  "when Peephole is enabled and CIFG is disabled. m_Parameters.m_PeepholeEnabled should be set "
3158  "appropriately.");
3159  }
3160 
3161  if (m_Parameters.m_PeepholeEnabled)
3162  {
3163  auto cellToForgetWeightsInfo = m_CellToForgetWeights->GetTensorInfo();
3164  ValidateTensorNumDimNumElem(cellToForgetWeightsInfo, 1, numUnits, " cellToForgetWeights");
3165  ValidateDataTypes(cellToForgetWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3166 
3167  auto cellToOutputWeightsInfo = m_CellToOutputWeights->GetTensorInfo();
3168  ValidateTensorNumDimNumElem(cellToOutputWeightsInfo, 1, numUnits, " cellToOutputWeights");
3169  ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToOutputWeightsInfo, descriptorName,
3170  "cellToForgetWeight", "cellToOutputWeights");
3171 
3172  if (!m_Parameters.m_CifgEnabled)
3173  {
3174  auto cellToInputWeightsInfo = m_CellToInputWeights->GetTensorInfo();
3175  ValidateTensorNumDimNumElem(cellToInputWeightsInfo, 1, numUnits, " cellToInputWeights");
3176  ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToInputWeightsInfo, descriptorName,
3177  "cellToForgetWeights", "cellToInputWeights");
3178  }
3179  }
3180 
3181  // Validate OPTIONAL params: Layer Norm Weights
3182  bool allLayerNormWeightsPresentOrNot =
3183  (((m_InputLayerNormWeights || m_Parameters.m_CifgEnabled) && m_ForgetLayerNormWeights
3184  && m_CellLayerNormWeights && m_OutputLayerNormWeights && m_Parameters.m_LayerNormEnabled)
3185  || (!m_InputLayerNormWeights && !m_ForgetLayerNormWeights && !m_CellLayerNormWeights
3186  && !m_OutputLayerNormWeights && !m_Parameters.m_LayerNormEnabled));
3187 
3188  if (!allLayerNormWeightsPresentOrNot)
3189  {
3190  throw InvalidArgumentException(descriptorName +
3191  ": InputLayerNormWeights, ForgetLayerNormWeights, m_OutputLayerNormWeights "
3192  "and CellLayerNormWeights should all be present (Layer Norm enabled) or not "
3193  "be present at all (Layer Norm disabled). InputLayerNormWeights should "
3194  "only be present when Layer Norm is enabled and CIFG is disabled. "
3195  "m_Parameters.m_LayerNormEnabled should be set appropriately.");
3196  }
3197 
3198  if (m_Parameters.m_LayerNormEnabled)
3199  {
3200  auto forgetLayerNormWeightsInfo = m_ForgetLayerNormWeights->GetTensorInfo();
3201  ValidateTensorNumDimNumElem(forgetLayerNormWeightsInfo, 1, numUnits, " forgetLayerNormWeights");
3202  ValidateDataTypes(forgetLayerNormWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3203 
3204  auto cellLayerNormWeightsInfo = m_CellLayerNormWeights->GetTensorInfo();
3205  ValidateTensorNumDimNumElem(cellLayerNormWeightsInfo, 1, numUnits, " cellLayerNormWeights");
3206  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, cellLayerNormWeightsInfo, descriptorName,
3207  "forgetLayerNormWeights", "cellLayerNormWeights");
3208 
3209  auto outputLayerNormWeightsInfo = m_OutputLayerNormWeights->GetTensorInfo();
3210  ValidateTensorNumDimNumElem(outputLayerNormWeightsInfo, 1, numUnits, " outputLayerNormWeights");
3211  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, outputLayerNormWeightsInfo, descriptorName,
3212  "forgetLayerNormWeights", "outputLayerNormWeights");
3213 
3214  if (!m_Parameters.m_CifgEnabled)
3215  {
3216  auto inputLayerNormWeightsInfo = m_InputLayerNormWeights->GetTensorInfo();
3217  ValidateTensorNumDimNumElem(inputLayerNormWeightsInfo, 1, numUnits, " inputLayerNormWeights");
3218  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, inputLayerNormWeightsInfo, descriptorName,
3219  "forgetLayerNormWeights", "inputLayerNormWeights");
3220  }
3221  }
3222 
3223  // Validate OPTIONAL params: Projection (projectionWeights, projectionBias)
3224  bool correctProjectionTensorsPresent =
3225  ((!m_ProjectionWeights && !m_ProjectionBias && !m_Parameters.m_ProjectionEnabled) ||
3226  (m_ProjectionWeights && !m_ProjectionBias && m_Parameters.m_ProjectionEnabled) ||
3227  (m_ProjectionWeights && m_ProjectionBias && m_Parameters.m_ProjectionEnabled));
3228 
3229  if (!correctProjectionTensorsPresent)
3230  {
3231  throw InvalidArgumentException(descriptorName +
3232  ": If projection is enabled, ProjectionWeights should be present and "
3233  "ProjectionBias is optional. If projection is disabled, neither "
3234  "ProjectionWeights nor ProjectionBias should be present.");
3235  }
3236 
3237  if (m_Parameters.m_ProjectionEnabled)
3238  {
3239  auto projectionWeightsInfo = m_ProjectionWeights->GetTensorInfo();
3240  ValidateTensorNumDimNumElem(projectionWeightsInfo, 2, (numUnits * outputSize), "ProjectionWeights");
3241  ValidateDataTypes(projectionWeightsInfo, weightsSupportedTypes, descriptorName);
3242 
3243  if (m_ProjectionBias)
3244  {
3245  auto projectionBiasInfo = m_ProjectionBias->GetTensorInfo();
3246  ValidateTensorNumDimNumElem(projectionBiasInfo, 1, outputSize, "ProjectionBias");
3247  ValidateDataTypes(projectionBiasInfo, biasSupportedTypes, descriptorName);
3248  }
3249 
3250  }
3251  else if ((outputInfo.GetQuantizationScale() != m_Parameters.m_HiddenStateScale) &&
3252  outputInfo.GetQuantizationOffset() != m_Parameters.m_HiddenStateZeroPoint) {
3253  throw InvalidArgumentException(descriptorName +
3254  ": If projection is disabled, output quantization info (scale, offset) "
3255  "should match HiddenStateScale and HiddenStateZeroPoint.");
3256  }
3257 
3258 }
3259 
3261 {
3262  const std::string descriptorName{"QuantizedLstmQueueDescriptor"};
3263 
3264  // Validate number of inputs/outputs
3265  ValidateNumInputs(workloadInfo, descriptorName, 3);
3266  ValidateNumOutputs(workloadInfo, descriptorName, 2);
3267 
3268  // Input/output tensor infos
3269  auto inputInfo = workloadInfo.m_InputTensorInfos[0];
3270  auto cellStateInInfo = workloadInfo.m_InputTensorInfos[1];
3271  auto outputStateInInfo = workloadInfo.m_InputTensorInfos[2];
3272 
3273  auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
3274  auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
3275 
3276  std::vector<DataType> inputOutputSupportedTypes =
3277  {
3279  };
3280 
3281  std::vector<DataType> cellStateSupportedTypes =
3282  {
3284  };
3285 
3286  std::vector<DataType> weightsSupportedTypes =
3287  {
3289  };
3290 
3291  std::vector<DataType> biasSupportedTypes =
3292  {
3294  };
3295 
3296  // Validate types of input/output tensors
3297  ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3298  ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3299  ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3300 
3301  ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3302  ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3303 
3304  // Validate matching types of input/output tensors
3305  ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3306  ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3307  "outputStateIn", "outputStateOut");
3308  ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3309 
3310  // Validate matching quantization info for input/output tensors
3311  ValidateTensorQuantizationSpace(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3312  ValidateTensorQuantizationSpace(inputInfo, outputStateOutInfo, descriptorName, "input", "outputStateOut");
3313  ValidateTensorQuantizationSpace(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3314 
3315  // Infer number of batches, input size and output size from tensor dimensions
3316  const uint32_t numBatches = inputInfo.GetShape()[0];
3317  const uint32_t inputSize = inputInfo.GetShape()[1];
3318  const uint32_t outputSize = cellStateInInfo.GetShape()[1];
3319 
3320  // Validate number of dimensions and number of elements for input/output tensors
3321  ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3322  ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * outputSize), descriptorName + " cellStateIn");
3323  ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3324  ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * outputSize), descriptorName + " cellStateOut");
3325  ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3326 
3327  // Validate number of dimensions and number of elements for weights tensors
3328  ValidatePointer(m_InputToInputWeights, descriptorName, "InputToInputWeights");
3329  auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3330  ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (outputSize * inputSize), " InputToInputWeights");
3331 
3332  ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3333  auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3334  ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (outputSize * inputSize), " InputToForgetWeights");
3335 
3336  ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3337  auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3338  ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (outputSize * inputSize), " InputToCellWeights");
3339 
3340  ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3341  auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3342  ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (outputSize * inputSize), " InputToOutputWeights");
3343 
3344  ValidatePointer(m_RecurrentToInputWeights, descriptorName, "RecurrentToInputWeights");
3345  auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3346  ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToInputWeights");
3347 
3348  ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3349  auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3350  ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (outputSize * outputSize),
3351  " RecurrentToForgetWeights");
3352 
3353  ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3354  auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3355  ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3356 
3357  ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3358  auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3359  ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3360 
3361  // Validate data types for weights tensors (all should match each other)
3362  ValidateDataTypes(inputToInputWeightsInfo, weightsSupportedTypes, descriptorName);
3363 
3364  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToForgetWeightsInfo, descriptorName,
3365  "inputToInputWeights", "inputToForgetWeights");
3366  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToCellWeightsInfo, descriptorName,
3367  "inputToInputWeights", "inputToCellWeights");
3368  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3369  "inputToInputWeights", "inputToOutputWeights");
3370 
3371  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3372  "inputToInputWeights", "recurrentToInputWeights");
3373  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3374  "inputToInputWeights", "recurrentToForgeteights");
3375  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3376  "inputToInputWeights", "recurrentToCellWeights");
3377  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3378  "inputToInputWeights", "recurrentToOutputWeights");
3379 
3380  // Validate matching quantization info for weight tensors (all should match each other)
3381  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToForgetWeightsInfo,
3382  descriptorName, "inputToInputWeights", "inputToForgetWeights");
3383  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToCellWeightsInfo,
3384  descriptorName, "inputToInputWeights", "inputToCellWeights");
3385  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToOutputWeightsInfo,
3386  descriptorName, "inputToInputWeights", "inputToOutputWeights");
3387 
3388  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToInputWeightsInfo,
3389  descriptorName, "inputToInputWeights", "recurrentToInputWeights");
3390  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToForgetWeightsInfo,
3391  descriptorName, "inputToInputWeights", "recurrentToForgetWeights");
3392  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToCellWeightsInfo,
3393  descriptorName, "inputToInputWeights", "recurrentToCellWeights");
3394  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToOutputWeightsInfo,
3395  descriptorName, "inputToInputWeights", "recurrentToOutputWeights");
3396 
3397  // Validate number of dimensions and number of elements in bias tensors
3398  ValidatePointer(m_InputGateBias, descriptorName, "InputGateBias");
3399  auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3400  ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, outputSize, " InputGateBias");
3401 
3402  ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3403  auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3404  ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, outputSize, " ForgetGateBias");
3405 
3406  ValidatePointer(m_CellBias, descriptorName, "CellBias");
3407  auto cellBiasInfo = m_CellBias->GetTensorInfo();
3408  ValidateTensorNumDimNumElem(cellBiasInfo, 1, outputSize, " CellBias");
3409 
3410  ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3411  auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3412  ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, outputSize, " OutputGateBias");
3413 
3414  // Validate data types for bias tensors (all should match each other)
3415  ValidateDataTypes(inputGateBiasInfo, biasSupportedTypes, descriptorName);
3416 
3417  ValidateTensorDataTypesMatch(inputGateBiasInfo, forgetGateBiasInfo, descriptorName,
3418  "inputGateBias", "forgetGateBias");
3419  ValidateTensorDataTypesMatch(inputGateBiasInfo, cellBiasInfo, descriptorName,
3420  "inputGateBias", "cellBias");
3421  ValidateTensorDataTypesMatch(inputGateBiasInfo, outputGateBiasInfo, descriptorName,
3422  "inputGateBias", "outputGateBias");
3423 
3424  // Validate bias tensor quantization info
3425  ValidateBiasTensorQuantization(inputGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3426  ValidateBiasTensorQuantization(forgetGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3427  ValidateBiasTensorQuantization(cellBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3428  ValidateBiasTensorQuantization(outputGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3429 }
3430 
3431 void AbsQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3432 {
3433  const std::string descriptorName{"AbsQueueDescriptor"};
3434 
3435  ValidateNumInputs(workloadInfo, descriptorName, 1);
3436  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3437 
3438  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3439  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3440 
3441  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3442 
3443  std::vector<DataType> supportedTypes =
3444  {
3452  };
3453 
3454  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3455  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3456 }
3457 
3458 void SliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3459 {
3460  const std::string descriptorName{"SliceQueueDescriptor"};
3461 
3462  ValidateNumInputs(workloadInfo, descriptorName, 1);
3463  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3464 
3465  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3466  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3467 
3468  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3469 
3470  const unsigned int rank = inputTensorInfo.GetNumDimensions();
3471  if (rank > 4)
3472  {
3473  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
3474  }
3475 
3476  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, rank, "output");
3477 
3478  // Check if m_Begin and m_Size have the expected length
3479  if (m_Parameters.m_Begin.size() != rank)
3480  {
3481  throw InvalidArgumentException(descriptorName +
3482  ": Length of begin offset descriptor must equal rank " + std::to_string(rank));
3483  }
3484  if (m_Parameters.m_Size.size() != rank)
3485  {
3486  throw InvalidArgumentException(descriptorName +
3487  ": Length of size descriptor must equal rank " + std::to_string(rank));
3488  }
3489 
3490  // Check if the shape of the output tensor matches m_Size
3491  const TensorShape& outputShape = outputTensorInfo.GetShape();
3492  for (unsigned int i = 0u; i < rank; ++i)
3493  {
3494  if (m_Parameters.m_Size[i] != outputShape[i])
3495  {
3496  throw InvalidArgumentException(descriptorName + ": Size descriptor does not match output tensor.");
3497  }
3498  }
3499 
3500  // Check if the sum of begin offset and size in a given dimension
3501  // does not exceed the size of corresponding input
3502  const TensorShape& inputShape = inputTensorInfo.GetShape();
3503  for(unsigned int i = 0u; i < rank; ++i)
3504  {
3505  if (m_Parameters.m_Begin[i] + m_Parameters.m_Size[i] > inputShape[i])
3506  {
3507  throw InvalidArgumentException(descriptorName + ": Sum of begin offset and size for dimension " +
3508  std::to_string(i) + " exceeds input size.");
3509  }
3510  }
3511 }
3512 
3514 {
3515  const std::string descriptorName{"DepthToSpaceQueueDescriptor"};
3516 
3517  ValidateNumInputs(workloadInfo, descriptorName, 1);
3518  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3519 
3520  const TensorInfo& inputInfo = workloadInfo.m_InputTensorInfos[0];
3521  const TensorInfo& outputInfo = workloadInfo.m_OutputTensorInfos[0];
3522 
3523  ValidateTensorNumDimensions(inputInfo, descriptorName, 4, "input");
3524  ValidateTensorNumDimensions(outputInfo, descriptorName, 4, "output");
3525 
3526  std::vector<DataType> supportedTypes =
3527  {
3534  };
3535 
3536  ValidateDataTypes(inputInfo, supportedTypes, descriptorName);
3537  ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
3538 
3539  ValidateTensorNumElementsMatch(inputInfo, outputInfo, descriptorName, "input", "output");
3540 
3541  if (m_Parameters.m_BlockSize == 0)
3542  {
3543  throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
3544  }
3545 
3546  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
3547  const unsigned int wIndex = dimensionIndices.GetWidthIndex();
3548  const unsigned int hIndex = dimensionIndices.GetHeightIndex();
3549  const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
3550 
3551  const TensorShape& outputShape = outputInfo.GetShape();
3552  if (outputShape[hIndex] % m_Parameters.m_BlockSize != 0 || outputShape[wIndex] % m_Parameters.m_BlockSize != 0)
3553  {
3554  throw InvalidArgumentException(descriptorName + ": Output width and height shape"
3555  "must be divisible by block size.");
3556  }
3557 
3558  const TensorShape& inputShape = inputInfo.GetShape();
3559  if (inputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
3560  {
3561  throw InvalidArgumentException(descriptorName + ": The depth of the input tensor"
3562  "must be divisible by the square of block size." );
3563  }
3564 }
3565 
3566 void ComparisonQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3567 {
3568  const std::string descriptorName{"ComparisonQueueDescriptor"};
3569 
3570  ValidateNumInputs(workloadInfo, descriptorName, 2);
3571  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3572 
3573  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3574  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3575  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3576 
3577  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3578  inputTensorInfo1,
3579  outputTensorInfo,
3580  descriptorName,
3581  "input_0",
3582  "input_1");
3583 
3584  if (outputTensorInfo.GetDataType() != DataType::Boolean)
3585  {
3586  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3587  }
3588 }
3589 
3591 {
3592  const std::string descriptorName{"ElementwiseUnaryQueueDescriptor"};
3593 
3594  ValidateNumInputs(workloadInfo, descriptorName, 1);
3595  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3596 
3597  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3598  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3599 
3600  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3601 
3602  std::vector<DataType> supportedTypes =
3603  {
3611  };
3612 
3613  std::vector<DataType> logicalSupportedTypes =
3614  {
3616  };
3617 
3618  if (m_Parameters.m_Operation == UnaryOperation::LogicalNot)
3619  {
3620  ValidateDataTypes(inputTensorInfo, logicalSupportedTypes, descriptorName);
3621  }
3622  else
3623  {
3624  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3625  }
3626 
3627 
3628  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3629 }
3630 
3631 void RankQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3632 {
3633  const std::string descriptorName{"RankQueueDescriptor"};
3634 
3635  ValidateNumInputs(workloadInfo, descriptorName, 1);
3636  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3637 
3638  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3639  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3640 
3641  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
3642  ValidateTensorNumElements(outputTensorInfo, descriptorName, 1, "output");
3643 
3644  std::vector<DataType> supportedTypes =
3645  {
3654  };
3655 
3656  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3657  ValidateDataTypes(outputTensorInfo, { DataType::Signed32 }, descriptorName);
3658 }
3659 
3661 {
3662  const std::string descriptorName{"LogicalBinaryQueueDescriptor"};
3663 
3664  ValidateNumInputs(workloadInfo, descriptorName, 2);
3665  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3666 
3667  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3668  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3669  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3670 
3671  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3672  inputTensorInfo1,
3673  outputTensorInfo,
3674  descriptorName,
3675  "input_0",
3676  "input_1");
3677 
3678  if (inputTensorInfo0.GetDataType() != DataType::Boolean)
3679  {
3680  throw InvalidArgumentException(descriptorName + ": Input tensor 0 type must be Boolean.");
3681  }
3682 
3683  if (inputTensorInfo1.GetDataType() != DataType::Boolean)
3684  {
3685  throw InvalidArgumentException(descriptorName + ": Input tensor 1 type must be Boolean.");
3686  }
3687 
3688  if (outputTensorInfo.GetDataType() != DataType::Boolean)
3689  {
3690  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3691  }
3692 }
3693 
3694 void ReduceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3695 {
3696  const std::string descriptorName{"ReduceQueueDescriptor"};
3697 
3698  ValidateNumInputs(workloadInfo, descriptorName, 1);
3699  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3700 
3701  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3702  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3703 
3704  std::vector<DataType> supportedTypes =
3705  {
3713  };
3714 
3715  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3716  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3717 }
3718 
3720 {
3721  // Modified from LstmQueueDescriptor::Validate to support UnidirectionalSequenceLstm
3722 
3723  const std::string descriptorName{"UnidirectionalSequenceLstmQueueDescriptor"};
3724 
3725  // check dimensions of all inputs and outputs
3726  if (workloadInfo.m_InputTensorInfos.size() != 3)
3727  {
3728  throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
3729  }
3730  if (workloadInfo.m_OutputTensorInfos.size() != 1)
3731  {
3732  throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
3733  }
3734 
3735  std::vector<DataType> supportedTypes =
3736  {
3738  };
3739 
3740  // check for supported type of one input and match them with all the other input and output
3741  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
3742 
3743  // type matches all other inputs
3744  for (uint32_t i = 1u; i < workloadInfo.m_InputTensorInfos.size(); ++i)
3745  {
3746  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
3747  workloadInfo.m_InputTensorInfos[i],
3748  descriptorName,
3749  "input_0",
3750  "input_" + std::to_string(i));
3751  }
3752  // type matches all other outputs
3753  for (uint32_t i = 0u; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
3754  {
3755  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
3756  workloadInfo.m_OutputTensorInfos[i],
3757  "LstmQueueDescriptor",
3758  "input_0",
3759  "output_" + std::to_string(i));
3760  }
3761 
3762  // Making sure clipping parameters have valid values.
3763  // == 0 means no clipping
3764  // > 0 means clipping
3765  if (m_Parameters.m_ClippingThresCell < 0.0f)
3766  {
3767  throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
3768  }
3769  if (m_Parameters.m_ClippingThresProj < 0.0f)
3770  {
3771  throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
3772  }
3773 
3774  unsigned int batchIndx = 0;
3775  unsigned int inputIndx = 1;
3776  uint32_t timeStep = 1;
3777  unsigned int timeIndx = 1;
3778  inputIndx = 2;
3779  if (m_Parameters.m_TimeMajor)
3780  {
3781  batchIndx = 1;
3782  timeIndx = 0;
3783 
3784  }
3785  timeStep = workloadInfo.m_InputTensorInfos[0].GetShape()[timeIndx];
3786 
3787  // Inferring batch size, number of outputs and number of cells from the inputs.
3788  const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[inputIndx];
3789  const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[batchIndx];
3790  ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
3791  const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
3792  ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
3793  const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
3794 
3795  // input tensor
3796  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 3, (timeStep * n_batch * n_input),
3797  descriptorName + " input_0");
3798  // outputStateInTensor
3799  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
3800  descriptorName + " input_1");
3801  // outputStateInTensor
3802  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
3803  descriptorName + " input_2");
3804 
3805  // outputTensor
3806  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[0], 3, (timeStep * n_batch * n_output),
3807  descriptorName + " output_0");
3808 
3809  // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
3810  if ( m_InputToInputWeights )
3811  {
3812  ValidateTensorNumDimNumElem(m_InputToInputWeights->GetTensorInfo(), 2,
3813  (n_cell * n_input), "InputLayerNormWeights");
3814  }
3815 
3816  ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
3817  ValidateTensorNumDimNumElem(m_InputToForgetWeights->GetTensorInfo(), 2,
3818  (n_cell * n_input), "InputToForgetWeights");
3819 
3820  ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
3821  ValidateTensorNumDimNumElem(m_InputToCellWeights->GetTensorInfo(), 2,
3822  (n_cell * n_input), "InputToCellWeights");
3823 
3824  if ( m_RecurrentToInputWeights )
3825  {
3826  ValidateTensorNumDimNumElem(m_RecurrentToInputWeights->GetTensorInfo(), 2,
3827  (n_cell * n_output), "RecurrentToInputWeights");
3828  }
3829 
3830  ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
3831  ValidateTensorNumDimNumElem(m_RecurrentToForgetWeights->GetTensorInfo(), 2,
3832  (n_cell * n_output), "RecurrentToForgetWeights");
3833 
3834  ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
3835  ValidateTensorNumDimNumElem(m_RecurrentToCellWeights->GetTensorInfo(), 2,
3836  (n_cell * n_output), "RecurrentToCellWeights");
3837 
3838  // Make sure the input-gate's parameters are either both present (regular
3839  // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
3840  bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
3841  !m_Parameters.m_CifgEnabled) ||
3842  (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
3843  m_Parameters.m_CifgEnabled));
3844  if (!cifg_weights_all_or_none)
3845  {
3846  throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
3847  "RecurrentToInputWeights must either both be present (regular LSTM) "
3848  "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
3849  "accordingly.");
3850  }
3851 
3852  if ( m_CellToInputWeights )
3853  {
3854  ValidateTensorNumDimNumElem(m_CellToInputWeights->GetTensorInfo(), 1,
3855  n_cell, "CellToInputWeights");
3856  }
3857  if ( m_CellToForgetWeights )
3858  {
3859  ValidateTensorNumDimNumElem(m_CellToForgetWeights->GetTensorInfo(), 1,
3860  n_cell, "CellToForgetWeights");
3861  }
3862  if ( m_CellToOutputWeights )
3863  {
3864  ValidateTensorNumDimNumElem(m_CellToOutputWeights->GetTensorInfo(), 1,
3865  n_cell, "CellToOutputWeights");
3866  }
3867 
3868  // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
3869  bool peephole_weights_all_or_none =
3870  (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
3871  && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
3872  || ( !m_CellToInputWeights && !m_CellToForgetWeights
3873  && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
3874  if (!peephole_weights_all_or_none)
3875  {
3876  throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
3877  }
3878 
3879  // Make sure the input gate bias is present only when not a CIFG-LSTM.
3880  if (m_Parameters.m_CifgEnabled)
3881  {
3882  if (m_InputGateBias)
3883  {
3884  throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
3885  }
3886  }
3887  else
3888  {
3889  if (!m_InputGateBias)
3890  {
3891  throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
3892  "must be present.");
3893  }
3894  ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1,
3895  n_cell, "InputGateBias");
3896  }
3897 
3898  ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
3899  ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
3900 
3901  ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
3902  ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
3903 
3904  ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
3905  ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
3906 
3907  if (m_ProjectionWeights)
3908  {
3909  ValidateTensorNumDimNumElem(m_ProjectionWeights->GetTensorInfo(), 2,
3910  (n_cell * n_output), "ProjectionWeights");
3911  }
3912  if (m_ProjectionBias)
3913  {
3914  ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
3915  }
3916 
3917  // Making sure the projection tensors are consistent:
3918  // 1) If projection weight is not present, then projection bias should not be
3919  // present.
3920  // 2) If projection weight is present, then projection bias is optional.
3921  bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
3922  !m_Parameters.m_ProjectionEnabled)
3923  || (m_ProjectionWeights && !m_ProjectionBias &&
3924  m_Parameters.m_ProjectionEnabled)
3925  || (m_ProjectionWeights && m_ProjectionBias &&
3926  m_Parameters.m_ProjectionEnabled));
3927  if (!projecton_tensors_consistent)
3928  {
3929  throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
3930  }
3931 
3932  // The four layer normalization weights either all have values or none of them have values. Additionally, if
3933  // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
3934  // either all have values or none of them have values. Layer normalization is used when the values of all the
3935  // layer normalization weights are present
3936  if (m_InputLayerNormWeights)
3937  {
3938  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
3939  }
3940  if (m_ForgetLayerNormWeights)
3941  {
3942  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
3943  }
3944  if (m_CellLayerNormWeights)
3945  {
3946  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
3947  }
3948  if (m_OutputLayerNormWeights)
3949  {
3950  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
3951  }
3952 
3953  if (m_Parameters.m_LayerNormEnabled)
3954  {
3955  if (!m_Parameters.m_CifgEnabled)
3956  {
3957  if (!m_InputLayerNormWeights)
3958  {
3959  throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
3960  "disabled but InputLayerNormWeights are not present");
3961  }
3962  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(),
3963  1, n_cell, "InputLayerNormWeights");
3964  }
3965  else if (m_InputLayerNormWeights)
3966  {
3967  throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
3968  "enabled");
3969  }
3970 
3971  ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
3972  "ForgetLayerNormWeights");
3973  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
3974 
3975  ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
3976  "OutputLayerNormWeights");
3977  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
3978 
3979  ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
3980  "CellLayerNormWeights");
3981  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
3982  }
3983  else if (m_InputLayerNormWeights || m_ForgetLayerNormWeights || m_OutputLayerNormWeights || m_CellLayerNormWeights)
3984  {
3985  throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
3986  "normalisation weights are present.");
3987  }
3988 }
3989 
3990 
3991 } // 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
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:434
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
unsigned int GetWidthIndex() const
std::vector< unsigned int > m_Origin
const TensorShape & GetShape() const
Definition: Tensor.hpp:191
constexpr bool IsQuantizedType()
Definition: TypesUtils.hpp:262
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
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:448
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
Optional< unsigned int > GetQuantizationDim() const
Definition: Tensor.cpp:496
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:202
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:275
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:453
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:193
constexpr bool IsQuantized8BitType(DataType dataType)
Definition: TypesUtils.hpp:267
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< TensorInfo > m_InputTensorInfos
void Validate(const WorkloadInfo &workloadInfo) const
DataType
Definition: Types.hpp:35
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
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:480
float GetQuantizationScale() const
Definition: Tensor.cpp:463
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
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:197
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 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
void Validate(const WorkloadInfo &workloadInfo) const
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:195
unsigned int GetChannelsIndex() const
bool IsQuantized() const
Definition: Tensor.cpp:506
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