ArmNN
 21.02
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 
12 #include <algorithm>
13 #include <iomanip>
14 #include <string>
15 #include <sstream>
16 
17 #include <fmt/format.h>
18 
19 using namespace armnnUtils;
20 
21 namespace armnn
22 {
23 
24 //---------------------------------------------------------------
26 {
27  switch (inputDataType)
28  {
29  case DataType::Float16:
30  return DataType::Float16;
31  case DataType::BFloat16:
32  case DataType::Float32:
33  return DataType::Float32;
34  case DataType::QAsymmS8:
35  return DataType::Signed32;
36  case DataType::QAsymmU8:
37  return DataType::Signed32;
38  case DataType::QSymmS8:
39  return DataType::Signed32;
40  case DataType::QSymmS16:
41  return DataType::Signed32;
42  default:
43  ARMNN_ASSERT_MSG(false, "Invalid input data type");
44  return DataType::Float32;
45  }
46 }
47 
48 namespace
49 {
50 
51 //---------------------------------------------------------------
52 //android ndk does not support std::to_string function.
53 template <typename T>
54 std::string to_string(T value)
55 {
56  std::ostringstream os;
57  os << value;
58  return os.str();
59 }
60 
61 //---------------------------------------------------------------
62 void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName)
63 {
64  if (!ptr)
65  {
66  throw InvalidArgumentException(descName + ": Invalid null pointer. The " +
67  paramName + " parameter must be set.");
68  }
69 }
70 
71 //---------------------------------------------------------------
72 void ValidateTensorShapesMatch(const TensorInfo& first,
73  const TensorInfo& second,
74  std::string const& descName,
75  std::string const& firstName,
76  std::string const& secondName)
77 {
78  if (first.GetShape() != second.GetShape())
79  {
80  throw InvalidArgumentException(descName + ": "
81  + firstName + " & " + secondName + " must have identical shapes");
82  }
83 }
84 
85 //---------------------------------------------------------------
86 void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
87 {
88  if (workloadInfo.m_InputTensorInfos.size() != expectedSize)
89  {
90  throw InvalidArgumentException(descName +
91  ": Requires exactly " + to_string(expectedSize) + "input(s). " +
92  to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided.");
93  }
94 }
95 
96 //---------------------------------------------------------------
97 void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
98 {
99  if (workloadInfo.m_OutputTensorInfos.size() != expectedSize)
100  {
101  throw InvalidArgumentException(descName +
102  ": Requires exactly " + to_string(expectedSize) + " output(s). " +
103  to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
104  }
105 }
106 
107 //---------------------------------------------------------------
108 void ValidateTensorNumDimensions(const TensorInfo& tensor,
109  std::string const& descName,
110  unsigned int numDimensions,
111  std::string const& tensorName)
112 {
113  if (tensor.GetNumDimensions() != numDimensions)
114  {
115  throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " +
116  to_string(tensor.GetNumDimensions()) + " dimensions for " +
117  tensorName + " tensor.");
118  }
119 }
120 
121 //---------------------------------------------------------------
122 void ValidateTensorNumElements(const TensorInfo& tensor,
123  std::string const& descName,
124  unsigned int numElements,
125  std::string const& tensorName)
126 {
127  if (tensor.GetNumElements() != numElements)
128  {
129  throw InvalidArgumentException(descName + ": Expected " + to_string(numElements) + " but got " +
130  to_string(tensor.GetNumElements()) + " elements for " +
131  tensorName + " tensor.");
132  }
133 }
134 
135 //---------------------------------------------------------------
136 void ValidateTensorNumDimNumElem(const TensorInfo& tensorInfo,
137  unsigned int numDimension,
138  unsigned int numElements,
139  std::string const& tensorName)
140 {
141  const std::string functionName{"ValidateTensorNumDimNumElem"};
142  ValidateTensorNumDimensions(tensorInfo, functionName, numDimension, tensorName);
143  ValidateTensorNumElements(tensorInfo, functionName, numElements, tensorName);
144 }
145 
146 //---------------------------------------------------------------
147 void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
148  const std::string& descName, std::string const& tensorName)
149 {
150  if (tensor.GetDataType() != dataType)
151  {
152  throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
153  GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
154  }
155 }
156 
157 void ValidPerAxisQuantizedDataType(const TensorInfo& tensor, const std::string& descName, const std::string& tensorName)
158 {
160  if (tensor.GetDataType() != DataType::QSymmS8 &&
161  tensor.GetDataType() != DataType::QuantizedSymm8PerAxis)
162  {
163  throw InvalidArgumentException(descName +
164  ": Expected data type which supports per-axis quantization scheme but got " +
165  GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
166  }
168 }
169 
170 //---------------------------------------------------------------
171 void ValidateTensorQuantizationSpace(const TensorInfo& first,
172  const TensorInfo& second,
173  const std::string& descName,
174  std::string const& firstName,
175  std::string const& secondName)
176 {
177  if (!first.IsQuantized() ||
178  !second.IsQuantized())
179  {
180  // Not a quantized type, ignore the validation
181  return;
182  }
183 
184  DataType firstDataType = first.GetDataType();
185  DataType secondDataType = second.GetDataType();
186 
187  if (firstDataType != secondDataType)
188  {
189  throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
190  " must be of the same quantized type, " +
191  firstName + " is " + GetDataTypeName(firstDataType) + ", " +
192  secondName + " is " + GetDataTypeName(secondDataType));
193  }
194 
195  if (!first.IsTypeSpaceMatch(second))
196  {
197  throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
198  " must have the same quantization space, " +
199  firstName + " has offset " + to_string(first.GetQuantizationOffset()) +
200  " and scale " + to_string(first.GetQuantizationScale()) + ", " +
201  secondName + " has offset " + to_string(second.GetQuantizationOffset()) +
202  " and scale " + to_string(second.GetQuantizationScale()));
203  }
204 }
205 
206 //---------------------------------------------------------------
207 void ValidateBiasTensorQuantization(const TensorInfo& biasTensor,
208  const TensorInfo& inputTensorInfo,
209  const TensorInfo& weightsTensorInfo,
210  const std::string& descName)
211 {
212  // Helper lambda function to validate a single bias quantization scale value
213  auto VerifyBiasQuantizationScale = [&descName](float biasScale, float expectedScale) -> void
214  {
215  constexpr float tolerance = 0.000001f;
216  if (std::abs(biasScale - expectedScale) > tolerance)
217  {
218  // Print the float values with extra precision to see very small differences
219  std::stringstream msg;
220  msg << std::setprecision(10) << descName << ": Expected " << expectedScale <<
221  " quantization scale for bias tensor (the product of the input and weight scales), but got " <<
222  biasScale;
223  throw InvalidArgumentException(msg.str(), CHECK_LOCATION());
224  }
225  };
226 
227  if (biasTensor.GetQuantizationOffset() != 0)
228  {
229  throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
230  to_string(biasTensor.GetQuantizationOffset()));
231  }
232 
233  if (biasTensor.HasMultipleQuantizationScales() || weightsTensorInfo.HasMultipleQuantizationScales())
234  {
235  // Validate per-axis quantization scales
236  const std::vector<float>& weightScales = weightsTensorInfo.GetQuantizationScales();
237  const std::vector<float>& biasScales = biasTensor.GetQuantizationScales();
238 
239  if (weightScales.size() != biasScales.size())
240  {
241  std::stringstream msg;
242  msg << descName << ": Expected matching number of per-axis quantization scales for weights and bias, "
243  << "but got different values. This is currently unsupported: weights=" << weightScales.size()
244  << ", biases=" << biasScales.size();
245  throw InvalidArgumentException(msg.str(), CHECK_LOCATION());
246  }
247 
248  for (size_t i = 0ul; i < biasScales.size(); ++i)
249  {
250  const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightScales[i];
251  VerifyBiasQuantizationScale(biasScales[i], expectedScale);
252  }
253  }
254  else
255  {
256  // Validate per-tensor quantization scale
257  const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightsTensorInfo.GetQuantizationScale();
258  VerifyBiasQuantizationScale(biasTensor.GetQuantizationScale(), expectedScale);
259  }
260 }
261 
262 //---------------------------------------------------------------
263 void ValidateTensors(const std::vector<ITensorHandle*>& vec,
264  unsigned int numExpected,
265  const std::string& descName,
266  const std::string& varName)
267 {
268  if (vec.empty() && numExpected > 0)
269  {
270  throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
271  }
272 
273  for (unsigned int i = 0; i < numExpected; ++i)
274  {
275  if (!vec[i])
276  {
277  throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
278  }
279  }
280 }
281 
282 //---------------------------------------------------------------
283 void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
284  const TensorInfo& second,
285  const TensorInfo& output,
286  std::string const& descName,
287  std::string const& firstName,
288  std::string const& secondName)
289 {
290  // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
291  // broadcasted.
292  if (first.GetNumDimensions() != second.GetNumDimensions())
293  {
294  throw InvalidArgumentException(descName + ": Tensors "
295  + firstName + " & " + secondName
296  + " must have the same number of dimensions in order to be broadcasted");
297  }
298  uint32_t numDims = first.GetNumDimensions();
299  std::vector<uint32_t> outputDims(numDims, 0u);
300  for (uint32_t i = 0; i < numDims; i++)
301  {
302  const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i];
303  const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1);
304  if (dimsNotEqual && dimsNotOne)
305  {
306  throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes");
307  }
308  outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]);
309  }
310  TensorShape broadcastShape = TensorShape(armnn::numeric_cast<unsigned int>(outputDims.size()), outputDims.data());
311  if (broadcastShape != output.GetShape())
312  {
313  throw InvalidArgumentException(descName + ": The tensor shape resulting from adding "
314  + firstName + " & " + secondName
315  + " does not match the output shape");
316  }
317 }
318 
319 //---------------------------------------------------------------
320 void ValidateDataTypes(const TensorInfo& info,
321  const std::vector<armnn::DataType>& supportedTypes,
322  std::string const& descName)
323 {
324  auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
325  if (iterator == supportedTypes.end())
326  {
327  throw InvalidArgumentException(descName + ": " + " Tensor type is not supported.");
328  }
329 }
330 
331 //---------------------------------------------------------------
332 void ValidateTensorDataTypesMatch(const TensorInfo& first,
333  const TensorInfo& second,
334  std::string const& descName,
335  std::string const& firstName,
336  std::string const& secondName)
337 {
338  if (first.GetDataType() != second.GetDataType())
339  {
340  throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
341  " must have identical data types.");
342  }
343 }
344 
345 //---------------------------------------------------------------
346 void ValidateTensorNumElementsMatch(const TensorInfo& first,
347  const TensorInfo& second,
348  std::string const& descName,
349  std::string const& firstName,
350  std::string const& secondName)
351 {
352  if (first.GetNumElements() != second.GetNumElements())
353  {
354  throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
355  " must have the same number of elements.");
356  }
357 }
358 
359 void ValidateWeightDataType(const TensorInfo& inputInfo,
360  const TensorInfo& weightInfo,
361  const std::string& descName)
362 {
363  const DataType inputType = inputInfo.GetDataType();
364  if (IsQuantized8BitType(inputType))
365  {
367  const std::vector<DataType> validTypes =
368  {
369  DataType::QAsymmS8,
370  DataType::QAsymmU8,
371  DataType::QSymmS8,
372  DataType::QuantizedSymm8PerAxis // deprecated
373  };
375 
376  ValidateDataTypes(weightInfo, validTypes, descName);
377  }
378  else
379  {
380  ValidateTensorDataTypesMatch(inputInfo, weightInfo, descName, "input", "weight");
381  }
382 }
383 
384 void ValidatePerAxisQuantizationDimension(const TensorInfo& tensorInfo,
385  const std::string& descName,
386  const std::string& tensorName)
387 {
388  const Optional<unsigned int>& quantizationDim = tensorInfo.GetQuantizationDim();
389  if (!quantizationDim.has_value())
390  {
391  throw InvalidArgumentException(fmt::format("{0}: Quantization dimension for per-axis quantization "
392  "not set on tensor {1}.", descName, tensorName));
393  }
394 
395  if (quantizationDim.value() != 0)
396  {
397  throw InvalidArgumentException(fmt::format(
398  "{0}: Quantization dimension for per-axis quantization expected to be 0 on tensor {1}, "
399  "but got: {2}", descName, tensorName, quantizationDim.value()));
400  }
401 }
402 
403 void ValidatePerAxisQuantizationOffset(const TensorInfo& tensorInfo,
404  const std::string& descName,
405  const std::string& tensorName)
406 {
407  int32_t quantizationOffset = tensorInfo.GetQuantizationOffset();
408  if (quantizationOffset != 0)
409  {
410  throw InvalidArgumentException(fmt::format(
411  "{0}: Quantization offset for per-axis quantization expected to be 0 on tensor {1}, but got: {2}",
412  descName, tensorName, quantizationOffset));
413  }
414 }
415 
416 void ValidatePerAxisQuantization(const TensorInfo& inputInfo,
417  const TensorInfo& outputInfo,
418  const TensorInfo& weightInfo,
419  const Optional<TensorInfo>& optionalBiasInfo,
420  const std::string& descName)
421 {
422  if (weightInfo.HasPerAxisQuantization())
423  {
424  const DataType inputDataType = inputInfo.GetDataType();
425  const DataType outputDataType = outputInfo.GetDataType();
426 
427  const bool canHavePerAxisQuantization = (IsQuantized8BitType(inputDataType)) && inputDataType == outputDataType;
428 
429  if (!canHavePerAxisQuantization)
430  {
431  throw InvalidArgumentException(fmt::format(
432  "{0}: Per-axis quantization parameters set on tensor {1}, but data type does not support "
433  "per-axis quantization.", descName, "weight"));
434  }
435 
436 
437  ValidPerAxisQuantizedDataType(weightInfo, descName, "weight");
438  ValidatePerAxisQuantizationDimension(weightInfo, descName, "weight");
439  ValidatePerAxisQuantizationOffset(weightInfo, descName, "weight");
440 
441  if (optionalBiasInfo.has_value())
442  {
443  const TensorInfo& biasInfo = optionalBiasInfo.value();
444  if (!biasInfo.HasPerAxisQuantization())
445  {
446  throw InvalidArgumentException(fmt::format(
447  "{}: Per-axis quantization parameters not set on bias tensor, "
448  "despite being set on weight tensor.", descName));
449  }
450 
451  ValidateTensorDataType(biasInfo, DataType::Signed32, descName, "bias");
452  ValidatePerAxisQuantizationDimension(biasInfo, descName, "bias");
453  ValidatePerAxisQuantizationOffset(biasInfo, descName, "bias");
454  }
455  }
456 }
457 
458 } // anonymous namespace
459 
460 void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
461  unsigned int numExpectedIn, unsigned int numExpectedOut) const
462 {
463  ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
464  ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
465 }
466 
467 //---------------------------------------------------------------
468 void MapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
469 {
470  const std::string descriptorName{"MapQueueDescriptor"};
471 
472  ValidateNumInputs(workloadInfo, descriptorName, 1);
473  ValidateNumOutputs(workloadInfo, descriptorName, 0);
474 
475  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
476  {
477  if (!m_Inputs[i])
478  {
480  fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
481  }
482  }
483 }
484 
485 //---------------------------------------------------------------
486 void UnmapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
487 {
488  const std::string descriptorName{"UnmapQueueDescriptor"};
489 
490  ValidateNumInputs(workloadInfo, descriptorName, 1);
491  ValidateNumOutputs(workloadInfo, descriptorName, 0);
492 
493  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
494  {
495  if (!m_Inputs[i])
496  {
498  fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
499  }
500  }
501 }
502 
503 //---------------------------------------------------------------
504 void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
505 {
506  const std::string descriptorName{"MemCopyQueueDescriptor"};
507 
508  ValidateNumInputs(workloadInfo, descriptorName, 1);
509  ValidateNumOutputs(workloadInfo, descriptorName , 1);
510 
511  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
512  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
513 
514  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
515  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
516 
517  if (m_Inputs.size() != m_Outputs.size())
518  {
519  throw InvalidArgumentException(fmt::format(
520  "{0}: Number of inputs ({1}) does not match the number of outputs ({2}).",
521  descriptorName, m_Inputs.size(), m_Outputs.size()));
522  }
523 
524  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
525  {
526  if (!m_Inputs[i])
527  {
528  throw InvalidArgumentException(fmt::format(
529  "{0}: Invalid NULL input {1}.", descriptorName, i));
530  }
531 
532  if (!m_Outputs[i])
533  {
534  throw InvalidArgumentException(fmt::format("{0}: Invalid NULL output {1}", descriptorName, i));
535  }
536  }
537 }
538 
539 //---------------------------------------------------------------
540 void MemImportQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
541 {
542  ValidateNumInputs(workloadInfo, "MemImportQueueDescriptor", 1);
543  ValidateNumOutputs(workloadInfo, "MemImportQueueDescriptor" , 1);
544 
545  if (workloadInfo.m_InputTensorInfos.size() != 1)
546  {
547  throw InvalidArgumentException(fmt::format("Number of input infos ({}) is not 1.",
548  workloadInfo.m_InputTensorInfos.size()));
549 
550  }
551 
552  if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
553  {
554  throw InvalidArgumentException(fmt::format(
555  "Number of input infos ({0}) does not match the number of output infos ({1})",
556  workloadInfo.m_InputTensorInfos.size(), workloadInfo.m_OutputTensorInfos.size()));
557  }
558 
559  for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
560  {
561  if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
562  workloadInfo.m_OutputTensorInfos[i].GetNumElements())
563  {
564  throw InvalidArgumentException(fmt::format(
565  "Number of elements for tensor input and output {} does not match", i ));
566  }
567  }
568 
569  if (m_Inputs.size() != 1)
570  {
571  throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
572  }
573 
574  if (m_Inputs.size() != m_Outputs.size())
575  {
576  throw InvalidArgumentException(fmt::format(
577  "Number of inputs ({0}) does not match the number of outputs ({1})",
578  m_Inputs.size(), m_Outputs.size()));
579  }
580 
581  for (unsigned int i = 0; i < m_Inputs.size(); ++i)
582  {
583  if (!m_Inputs[i])
584  {
585  throw InvalidArgumentException(fmt::format("Invalid null input {}", i));
586  }
587 
588  if (!m_Outputs[i])
589  {
590  throw InvalidArgumentException(fmt::format("Invalid null output {}", i));
591  }
592  }
593 }
594 
595 //---------------------------------------------------------------
596 void MemSyncQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
597 {
598  ValidateNumInputs(workloadInfo, "MemSyncQueueDescriptor", 1);
599  ValidateNumOutputs(workloadInfo, "MemSyncQueueDescriptor" , 1);
600 
601  if (m_Inputs.size() != 1)
602  {
603  throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
604  }
605 
606  if (m_Outputs.size() != 0)
607  {
608  throw InvalidArgumentException(fmt::format("Number of outputs ({}) is not 0.", m_Outputs.size()));
609  }
610 
611  if (!m_Inputs[0])
612  {
613  throw InvalidArgumentException(fmt::format("Invalid null input 0"));
614  }
615 }
616 
617 //---------------------------------------------------------------
618 void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
619 {
620  const std::string descriptorName{"ActivationQueueDescriptor"};
621 
622  ValidateNumInputs(workloadInfo, descriptorName, 1);
623  ValidateNumOutputs(workloadInfo, descriptorName, 1);
624 
625  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
626  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
627 
628  std::vector<DataType> supportedTypes =
629  {
636  };
637 
638  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
639  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
640  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
641 }
642 
643 void ArgMinMaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
644 {
645  const std::string descriptorName{"ArgMinMaxQueueDescriptor"};
646 
647  ValidateNumInputs(workloadInfo, descriptorName, 1);
648  ValidateNumOutputs(workloadInfo, descriptorName, 1);
649 
650  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
651  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
652 
653  if (outputTensorInfo.GetDataType() != DataType::Signed32 &&
654  outputTensorInfo.GetDataType() != DataType::Signed64)
655  {
656  throw InvalidArgumentException(descriptorName + ": Output of ArgMinMax layer must be Int32 or Int64.");
657  }
658 
659  std::vector<DataType> supportedInputTypes =
660  {
669  };
670 
671  ValidateDataTypes(inputTensorInfo, supportedInputTypes, descriptorName);
672 
673  auto inputShape = inputTensorInfo.GetShape();
674  auto outputShape = outputTensorInfo.GetShape();
675 
676  auto inputNumDimensions = inputShape.GetNumDimensions();
677  auto unsignedAxis = armnnUtils::GetUnsignedAxis(inputNumDimensions, m_Parameters.m_Axis);
678 
679  const std::string outputShapeError{": Output tensor shape does not match shape inferred from input tensor."};
680 
681  // 1D input shape results in scalar output shape
682  if (inputShape.GetNumDimensions() == 1)
683  {
684  if (outputShape.GetNumDimensions() != 1 && outputShape[0] != 1)
685  {
686  throw InvalidArgumentException(descriptorName + outputShapeError);
687  }
688  }
689  else
690  {
691  for (unsigned int i = 0; i < unsignedAxis; ++i)
692  {
693  if (outputShape[i] != inputShape[i])
694  {
695  throw InvalidArgumentException(descriptorName + outputShapeError);
696  }
697  }
698 
699  for (auto i = unsignedAxis + 1; i < inputNumDimensions; ++i)
700  {
701  if (outputShape[i - 1] != inputShape[i])
702  {
703  throw InvalidArgumentException(descriptorName + outputShapeError);
704  }
705  }
706  }
707 }
708 
709 void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
710 {
711  const std::string descriptorName{"SoftmaxQueueDescriptor"};
712 
713  ValidateNumInputs(workloadInfo, descriptorName, 1);
714  ValidateNumOutputs(workloadInfo, descriptorName, 1);
715 
716  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
717  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
718 
719  std::vector<DataType> supportedTypes =
720  {
727  };
728 
729  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
730  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
731  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
732 }
733 
734 void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
735 {
736  const std::string descriptorName{"SplitterQueueDescriptor"};
737 
738  ValidateNumInputs(workloadInfo, descriptorName, 1);
739 
740  // Check the supported data types
741  std::vector<DataType> supportedTypes =
742  {
751  };
752 
753  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
754  for (unsigned long i = 0ul; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
755  {
756  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[i];
757  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
758 
759  const std::string outputName = "output_" + std::to_string(i);
760  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", outputName);
761  }
762 
763  if (workloadInfo.m_OutputTensorInfos.size() <= 0)
764  {
765  throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
766  }
767 
768  if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
769  {
771  descriptorName + ": Number of split windows "
772  "has to match number of workloadInfo.m_OutputTensorInfos. "
773  "Number of windows: " +
774  to_string(m_ViewOrigins.size()) +
775  ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
776  }
777 
778  //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
779  std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
780  for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
781  {
782  //Checks that the dimensionality of input is same as the split windows.
783  ViewOrigin const& e = m_ViewOrigins[w];
784  if (e.m_Origin.size() != inputDims)
785  {
786  throw InvalidArgumentException(descriptorName + ": Window origin have to "
787  "have the same dimensionality as the input tensor. "
788  "Window origin (index: " +
789  to_string(w) + ") has " + to_string(e.m_Origin.size()) +
790  " dimensions, the input "
791  "tensor has " +
792  to_string(inputDims) + " dimensions.");
793  }
794  for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
795  {
796  if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
797  workloadInfo.m_InputTensorInfos[0].GetShape()[i])
798  {
799  throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
800  "be smaller or equal than the size of the input in that coord.");
801  }
802  }
803  }
804 }
805 
806 void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
807 {
808  const std::string descriptorName{"ConcatQueueDescriptor"};
809 
810  ValidateNumOutputs(workloadInfo, descriptorName, 1);
811 
812  if (m_Inputs.size() <= 0)
813  {
814  throw InvalidArgumentException(descriptorName + ": At least one input needs to be provided.");
815  }
816  if (m_Outputs.size() <= 0)
817  {
818  throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
819  }
820 
821  if (workloadInfo.m_InputTensorInfos.size() <= 0)
822  {
823  throw InvalidArgumentException(descriptorName + ": At least one TensorInfo input needs to be provided.");
824  }
825  if (workloadInfo.m_OutputTensorInfos.size() <= 0)
826  {
827  throw InvalidArgumentException(descriptorName + ": At least one TensorInfo output needs to be provided.");
828  }
829 
830  if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
831  {
832  throw InvalidArgumentException(descriptorName + ": Invalid concatenation axis provided.");
833  }
834 
835  if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
836  {
837  return;
838  }
839 
840  if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
841  {
843  descriptorName + ": Number of split windows "
844  "has to match number of workloadInfo.m_InputTensorInfos. "
845  "Number of windows: " +
846  to_string(m_ViewOrigins.size()) +
847  ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
848  }
849 
850  //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
851  std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
852  for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
853  {
854  //Checks that the dimensionality of output is same as the split windows.
855  ViewOrigin const& e = m_ViewOrigins[w];
856  if (e.m_Origin.size() != outputDims)
857  {
858  throw InvalidArgumentException(descriptorName + ": Window origin have to "
859  "have the same dimensionality as the output tensor. "
860  "Window origin (index: " +
861  to_string(w) + ") has " + to_string(e.m_Origin.size()) +
862  " dimensions, the output "
863  "tensor has " +
864  to_string(outputDims) + " dimensions.");
865  }
866  //Checks that the merge windows are within the output tensor.
867  for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
868  {
869  if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
870  > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
871  {
872  throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
873  "be smaller or equal than the size of the output in that coord.");
874  }
875  }
876  }
877 
878  // Check the supported data types
879  std::vector<DataType> supportedTypes =
880  {
889  };
890 
891  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
892  for (unsigned long i = 0ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
893  {
894  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[i];
895  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
896 
897  const std::string inputName = "input_" + std::to_string(i);
898  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, inputName, "output");
899  }
900 }
901 
902 void StackQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
903 {
904  const std::string descriptorName{"StackQueueDescriptor"};
905 
906  ValidateNumOutputs(workloadInfo, descriptorName, 1);
907 
908  if (m_Parameters.m_NumInputs != workloadInfo.m_InputTensorInfos.size())
909  {
910  throw InvalidArgumentException(descriptorName + ": Must have the defined number of input tensors.");
911  }
912 
913  // All inputs must have the same shape, which is defined in parameters
914  const TensorShape& inputShape = m_Parameters.m_InputShape;
915  for (unsigned int i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
916  {
917  if (workloadInfo.m_InputTensorInfos[i].GetShape() != inputShape)
918  {
919  throw InvalidArgumentException(descriptorName + ": All input tensor shapes must match the defined shape.");
920  }
921  }
922 
923  if (inputShape.GetNumDimensions() > 4)
924  {
925  throw InvalidArgumentException(descriptorName + ": Input tensor may have up to 4 dimensions.");
926  }
927 
928  // m_Axis is 0-based and may take values from 0 to the number of input dimensions (inclusive),
929  // since the output tensor has an additional dimension.
930  if (m_Parameters.m_Axis > inputShape.GetNumDimensions())
931  {
932  throw InvalidArgumentException(descriptorName + ": Axis may not be greater "
933  "than the number of input dimensions.");
934  }
935 
936  // Output shape must be as inferred from the input shape
937  const TensorShape& outputShape = workloadInfo.m_OutputTensorInfos[0].GetShape();
938  for (unsigned int i = 0; i < m_Parameters.m_Axis; ++i)
939  {
940  if (outputShape[i] != inputShape[i])
941  {
942  throw InvalidArgumentException(descriptorName + ": Output tensor must "
943  "match shape inferred from input tensor.");
944  }
945  }
946 
947  if (outputShape[m_Parameters.m_Axis] != m_Parameters.m_NumInputs)
948  {
949  throw InvalidArgumentException(descriptorName + ": Output tensor must "
950  "match shape inferred from input tensor.");
951  }
952 
953  for (unsigned int i = m_Parameters.m_Axis + 1; i < inputShape.GetNumDimensions() + 1; ++i)
954  {
955  if (outputShape[i] != inputShape[i-1])
956  {
957  throw InvalidArgumentException(descriptorName + ": Output tensor must "
958  "match shape inferred from input tensor.");
959  }
960  }
961 
962  if (outputShape.GetNumDimensions() > 5)
963  {
964  throw InvalidArgumentException(descriptorName + ": Output tensor may have up to 5 dimensions.");
965  }
966 
967  // Check the supported data types
968  std::vector<DataType> supportedTypes =
969  {
978  };
979 
980  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
981 
982  for (unsigned int i = 1ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
983  {
984  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
985  workloadInfo.m_InputTensorInfos[i],
986  descriptorName,
987  "input_0",
988  "input_" + std::to_string(i));
989  }
990 
991  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
992  workloadInfo.m_OutputTensorInfos[0],
993  descriptorName,
994  "input_0",
995  "output");
996 }
997 
998 void FillQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
999 {
1000  const std::string descriptorName{"FillQueueDescriptor"};
1001 
1002  ValidateNumInputs(workloadInfo, descriptorName, 1);
1003  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1004 
1005  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1006  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1007 
1008  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 1, "input");
1009 
1010  std::vector<DataType> supportedTypes =
1011  {
1016  };
1017 
1018  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1019 }
1020 
1022 {
1023  const std::string descriptorName{"FullyConnectedQueueDescriptor"};
1024 
1025  ValidateNumInputs(workloadInfo, descriptorName, 1);
1026  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1027 
1028  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1029  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1030 
1031  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1032 
1033  if (!(inputTensorInfo.GetNumDimensions() == 2 || inputTensorInfo.GetNumDimensions() == 4))
1034  {
1035  throw InvalidArgumentException(descriptorName + ": Input tensor must have 2 or 4 dimensions.");
1036  }
1037 
1038  ValidatePointer(m_Weight, descriptorName, "weight");
1039 
1040  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
1041  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 2, "weight");
1042 
1043  if (m_Parameters.m_BiasEnabled)
1044  {
1045  ValidatePointer(m_Bias, descriptorName, "bias");
1046 
1047  // Validates type and quantization values.
1048  const TensorInfo& biasTensorInfo = m_Bias->GetTensorInfo();
1049  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1050 
1051  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1052  ValidateTensorNumDimensions(biasTensorInfo, descriptorName, 1, "bias");
1053  }
1054 
1055  // Check the supported data types
1056  std::vector<DataType> supportedTypes =
1057  {
1064  };
1065 
1066  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1067 
1068  // For FullyConnected, we allow to have BFloat16 input with Float32 output for optimization.
1069  if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1070  {
1071  if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1072  {
1073  throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1074  "for BFloat16 input.");
1075  }
1076  }
1077  else
1078  {
1079  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1080  }
1081 }
1082 
1084 {
1085  const std::string descriptorName{"NormalizationQueueDescriptor"};
1086 
1087  ValidateNumInputs(workloadInfo, descriptorName, 1);
1088  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1089 
1090  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1091  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1092 
1093  // Check the supported data types
1094  std::vector<DataType> supportedTypes =
1095  {
1102  };
1103 
1104  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1105 
1106  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1107 
1108  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1109 }
1110 
1111 void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1112 {
1113  const std::string descriptorName{"AdditionQueueDescriptor"};
1114 
1115  ValidateNumInputs(workloadInfo, descriptorName, 2);
1116  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1117 
1118  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1119  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1120  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1121 
1122  std::vector<DataType> supportedTypes =
1123  {
1131  };
1132 
1133  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1134  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1135  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1136 
1137  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1138  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1139 
1140  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1141  inputTensorInfo1,
1142  outputTensorInfo,
1143  descriptorName,
1144  "input_0",
1145  "input_1");
1146 }
1147 
1149 {
1150  const std::string descriptorName{"MultiplicationQueueDescriptor"};
1151 
1152  ValidateNumInputs(workloadInfo, descriptorName, 2);
1153  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1154 
1155  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1156  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1157  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1158 
1159  std::vector<DataType> supportedTypes =
1160  {
1168  };
1169 
1170  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1171  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1172  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1173 
1174  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1175  ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1176 
1177  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1178  inputTensorInfo1,
1179  outputTensorInfo,
1180  descriptorName,
1181  "input_0",
1182  "input_1");
1183 }
1184 
1186 {
1187  const std::string descriptorName{"BatchNormalizationQueueDescriptor"};
1188 
1189  ValidateNumInputs(workloadInfo, descriptorName, 1);
1190  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1191 
1192  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1193  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1194 
1195  std::vector<DataType> supportedTypes =
1196  {
1203  };
1204 
1205  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1206  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1207 
1208  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1209  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1210 
1211  ValidatePointer(m_Mean, descriptorName, "mean");
1212  ValidatePointer(m_Variance, descriptorName, "variance");
1213  ValidatePointer(m_Beta, descriptorName, "beta");
1214  ValidatePointer(m_Gamma, descriptorName, "gamma");
1215 
1216  const TensorInfo& mean = m_Mean->GetTensorInfo();
1217  const TensorInfo& variance = m_Variance->GetTensorInfo();
1218  const TensorInfo& beta = m_Beta->GetTensorInfo();
1219  const TensorInfo& gamma = m_Gamma->GetTensorInfo();
1220 
1221  ValidateTensorNumDimensions(mean, descriptorName, 1, "mean");
1222  ValidateTensorNumDimensions(variance, descriptorName, 1, "variance");
1223  ValidateTensorNumDimensions(beta, descriptorName, 1, "beta");
1224  ValidateTensorNumDimensions(gamma, descriptorName, 1, "gamma");
1225 
1226  ValidateTensorShapesMatch(mean, variance, descriptorName, "mean", "variance");
1227  ValidateTensorShapesMatch(mean, beta, descriptorName, "mean", "beta");
1228  ValidateTensorShapesMatch(mean, gamma, descriptorName, "mean", "gamma");
1229 }
1230 
1232 {
1233  const std::string descriptorName{"Convolution2dQueueDescriptor"};
1234 
1235  ValidateNumInputs(workloadInfo, descriptorName, 1);
1236  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1237 
1238  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1239  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1240 
1241  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1242  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1243 
1244  ValidatePointer(m_Weight, descriptorName, "weight");
1245 
1246  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
1247  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1248 
1249  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1250 
1251  Optional<TensorInfo> optionalBiasTensorInfo;
1252  if (m_Parameters.m_BiasEnabled)
1253  {
1254  ValidatePointer(m_Bias, descriptorName, "bias");
1255 
1256  optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
1257  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1258 
1259  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1260  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1261  }
1262 
1263  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1264  {
1266  fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1267  "cannot be either negative or 0.",
1268  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1269  }
1270 
1271  ValidatePerAxisQuantization(inputTensorInfo,
1272  outputTensorInfo,
1273  weightTensorInfo,
1274  optionalBiasTensorInfo,
1275  descriptorName);
1276 
1277  std::vector<DataType> supportedTypes =
1278  {
1286  };
1287 
1288  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1289 
1290  // For Convolution2d, we allow to have BFloat16 input with Float32 output for optimization.
1291  if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1292  {
1293  if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1294  {
1295  throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1296  "for BFloat16 input.");
1297  }
1298  }
1299  else
1300  {
1301  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1302  }
1303 }
1304 
1306 {
1307  const std::string descriptorName{"DepthwiseConvolution2dQueueDescriptor"};
1308 
1309  ValidateNumInputs(workloadInfo, descriptorName, 1);
1310  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1311 
1312  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1313  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1314 
1315  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1316  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1317 
1318  ValidatePointer(m_Weight, descriptorName, "weight");
1319 
1320  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
1321  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1322 
1323  if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 )
1324  {
1326  fmt::format("{}: dilationX (provided {}) and dilationY (provided {}) "
1327  "cannot be smaller than 1.",
1328  descriptorName, m_Parameters.m_DilationX, m_Parameters.m_DilationX));
1329  }
1330 
1331  if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1332  {
1334  fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1335  "cannot be either negative or 0.",
1336  descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1337  }
1338 
1339  const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
1340 
1341  // Expected weight shape: [ M, I, H, W ] - This shape does NOT depend on the data layout
1342  // inputChannels * channelMultiplier should be equal to outputChannels.
1343  const unsigned int numWeightChannelMultiplier = weightTensorInfo.GetShape()[0];
1344  const unsigned int numWeightInputChannels = weightTensorInfo.GetShape()[1];
1345  const unsigned int numWeightOutputChannels = outputTensorInfo.GetShape()[channelIndex];
1346  if (numWeightChannelMultiplier * numWeightInputChannels != numWeightOutputChannels)
1347  {
1348  throw InvalidArgumentException(fmt::format(
1349  "{0}: output_channels (provided {1}) should be equal to input_channels (provided {2}) "
1350  "multiplied by channel_multiplier (provided {3}).",
1351  descriptorName, numWeightOutputChannels, numWeightInputChannels, numWeightChannelMultiplier));
1352  }
1353 
1354  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1355 
1356  Optional<TensorInfo> optionalBiasTensorInfo;
1357  if (m_Parameters.m_BiasEnabled)
1358  {
1359  ValidatePointer(m_Bias, descriptorName, "bias");
1360 
1361  optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
1362  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1363 
1364  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
1365  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1366  }
1367  ValidatePerAxisQuantization(inputTensorInfo,
1368  outputTensorInfo,
1369  weightTensorInfo,
1370  optionalBiasTensorInfo,
1371  descriptorName);
1372 
1373  std::vector<DataType> supportedTypes =
1374  {
1381  };
1382 
1383  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1384  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1385 }
1386 
1387 void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1388 {
1389  const std::string descriptorName{"PermuteQueueDescriptor"};
1390 
1391  ValidateNumInputs(workloadInfo, descriptorName, 1);
1392  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1393 
1394  const PermutationVector& mapping = m_Parameters.m_DimMappings;
1395 
1396  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1397  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1398 
1399  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
1400  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
1401 
1402  for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
1403  {
1404  if (inputTensorInfo.GetShape()[i] != outputTensorInfo.GetShape()[mapping[i]])
1405  {
1406  throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(i) +
1407  " (=" + to_string(inputTensorInfo.GetShape()[i]) + ") " +
1408  "must match dst dimension " + to_string(mapping[i]) +
1409  " (=" + to_string(outputTensorInfo.GetShape()[mapping[i]]) + ")");
1410  }
1411  }
1412 
1413  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1414 }
1415 
1416 void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1417 {
1418  const std::string descriptorName{"Pooling2dQueueDescriptor"};
1419 
1420  ValidateNumInputs(workloadInfo, descriptorName, 1);
1421  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1422 
1423  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1424  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1425 
1426  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1427  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1428 
1429  std::vector<DataType> supportedTypes =
1430  {
1437  };
1438 
1439  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1440  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1441 }
1442 
1444 {
1445  const std::string descriptorName{"ResizeBilinearQueueDescriptor"};
1446 
1447  ValidateNumInputs(workloadInfo, descriptorName, 1);
1448  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1449 
1450  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1451  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1452 
1453  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1454  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1455 
1456  std::vector<DataType> supportedTypes =
1457  {
1464  };
1465 
1466  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1467  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1468 
1469  // ResizeBilinear only changes width and height: batch and channel count must match.
1470  const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0];
1471  const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0];
1472  if (inputBatchSize != outputBatchSize)
1473  {
1475  fmt::format("{}: Input batch size ({}) does not match output batch size ({})",
1476  descriptorName, inputBatchSize, outputBatchSize));
1477  }
1478 
1479  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1480  const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1481  const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1482  if (inputChannelCount != outputChannelCount)
1483  {
1485  fmt::format("{}: Input channel count ({}) does not match output channel count ({})",
1486  descriptorName, inputChannelCount, outputChannelCount));
1487  }
1488 }
1489 
1490 void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1491 {
1492  const std::string descriptorName{"ResizeQueueDescriptor"};
1493 
1494  ValidateNumInputs(workloadInfo, descriptorName, 1);
1495  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1496 
1497  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1498  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1499 
1500  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1501  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1502 
1503  std::vector<DataType> supportedTypes =
1504  {
1511  };
1512 
1513  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1514  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1515 
1516  // Resize only changes width and height: batch and channel count must match.
1517  const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0];
1518  const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0];
1519  if (inputBatchSize != outputBatchSize)
1520  {
1522  fmt::format("{}: Input batch size ({}) does not match output batch size ({})",
1523  descriptorName, inputBatchSize, outputBatchSize));
1524  }
1525 
1526  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1527  const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1528  const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1529  if (inputChannelCount != outputChannelCount)
1530  {
1532  fmt::format("{}: Input channel count ({}) does not match output channel count ({})",
1533  descriptorName, inputChannelCount, outputChannelCount));
1534  }
1535 }
1536 
1538 {
1539  const std::string descriptorName{"FakeQuantizationQueueDescriptor"};
1540 
1541  ValidateNumInputs(workloadInfo, descriptorName, 1);
1542  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1543 
1544  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1545  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1546 
1547  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 2, "input");
1548  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1549 
1550  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1551 
1552  if (m_Parameters.m_Min > m_Parameters.m_Max)
1553  {
1554  throw InvalidArgumentException(descriptorName + ": min cannot be greater than max");
1555  }
1556 }
1557 
1559 {
1560  const std::string descriptorName{"InstanceNormalizationQueueDescriptor"};
1561 
1562  ValidateNumInputs(workloadInfo, descriptorName, 1);
1563  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1564 
1565  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1566  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1567 
1568  if (inputTensorInfo.GetNumDimensions() > 4)
1569  {
1570  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1571  }
1572 
1573  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1574 
1575  // Check the supported data types
1576  std::vector<DataType> supportedTypes =
1577  {
1581  };
1582 
1583  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1584  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1585 }
1586 
1588 {
1589  const std::string descriptorName{"L2NormalizationQueueDescriptor"};
1590 
1591  ValidateNumInputs(workloadInfo, descriptorName, 1);
1592  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1593 
1594  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1595  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1596 
1597  if (inputTensorInfo.GetNumDimensions() > 4)
1598  {
1599  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1600  }
1601 
1602  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1603 
1604  // Check the supported data types
1605  std::vector<DataType> supportedTypes =
1606  {
1613  };
1614 
1615  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1616  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1617 }
1618 
1619 void LogSoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1620 {
1621  const std::string descriptorName{"LogSoftmaxQueueDescriptor"};
1622 
1623  ValidateNumInputs(workloadInfo, descriptorName, 1);
1624  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1625 
1626  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1627  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1628 
1629  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1630 
1631  std::vector<DataType> supportedTypes =
1632  {
1636  };
1637 
1638  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1639  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1640 }
1641 
1642 void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1643 {
1644  const std::string descriptorName{"ConstantQueueDescriptor"};
1645 
1646  ValidateNumInputs(workloadInfo, descriptorName, 0);
1647  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1648 
1649  if (!m_LayerOutput)
1650  {
1651  throw InvalidArgumentException(descriptorName + ": No const input specified.");
1652  }
1653 
1654  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1655  ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(), outputTensorInfo, descriptorName, "constant", "output");
1656 
1657  // Check the supported data types
1658  std::vector<DataType> supportedTypes =
1659  {
1668  };
1669 
1670  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1671 }
1672 
1673 void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1674 {
1675  const std::string descriptorName{"ReshapeQueueDescriptor"};
1676 
1677  ValidateNumInputs(workloadInfo, descriptorName, 1);
1678  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1679 
1680  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1681  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1682 
1683  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1684 
1685  // Check the supported data types
1686  std::vector<DataType> supportedTypes =
1687  {
1696  };
1697 
1698  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1699  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1700 }
1701 
1703 {
1704  const std::string descriptorName{"SpaceToBatchNdQueueDescriptor"};
1705 
1706  ValidateNumInputs(workloadInfo, descriptorName, 1);
1707  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1708 
1709  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1710  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1711 
1712  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1713  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1714 
1715  if (m_Parameters.m_BlockShape.size() != 2)
1716  {
1717  throw InvalidArgumentException(descriptorName + ": Block Shape must contain 2 spatial dimensions.");
1718  }
1719 
1720  if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
1721  {
1722  throw InvalidArgumentException(descriptorName + ": Pad List must contain the same number of "
1723  "dimensions as Block Shape.");
1724  }
1725 
1726  const TensorShape& inputShape = inputTensorInfo.GetShape();
1727 
1728  std::pair<unsigned int, unsigned int> heightPad = m_Parameters.m_PadList[0];
1729  std::pair<unsigned int, unsigned int> widthPad = m_Parameters.m_PadList[1];
1730 
1731  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1732 
1733  const unsigned int inputWidth = inputShape[dimensionIndices.GetWidthIndex()] +
1734  widthPad.first + widthPad.second;
1735  const unsigned int inputHeight = inputShape[dimensionIndices.GetHeightIndex()] +
1736  heightPad.first + heightPad.second;
1737 
1738  const unsigned int numInputElements = inputShape[0] * inputHeight * inputWidth *
1739  inputShape[dimensionIndices.GetChannelsIndex()];
1740  const unsigned int numOutputElements = outputTensorInfo.GetNumElements();
1741 
1742  if (numOutputElements != numInputElements)
1743  {
1744  throw InvalidArgumentException(descriptorName + ": Input tensor has " +
1745  to_string(numInputElements) + " after padding but output tensor has " +
1746  to_string(numOutputElements) + " elements.");
1747  }
1748 
1749  if (inputHeight % m_Parameters.m_BlockShape[0] != 0 || inputWidth % m_Parameters.m_BlockShape[1] != 0)
1750  {
1751  throw InvalidArgumentException(descriptorName + ": Input shape after padding must be "
1752  "divisible by Block Shape in all spatial dimensions");
1753  }
1754 
1755  std::vector<DataType> supportedTypes =
1756  {
1763  };
1764 
1765  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1766  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1767 }
1768 
1770 {
1771  const std::string descriptorName{"SpaceToDepthQueueDescriptor"};
1772 
1773  ValidateNumInputs(workloadInfo, descriptorName, 1);
1774  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1775 
1776  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1777  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1778 
1779  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1780  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1781 
1782  std::vector<DataType> supportedTypes =
1783  {
1790  };
1791 
1792  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1793  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1794 
1795  ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1796 
1797  if (m_Parameters.m_BlockSize == 0)
1798  {
1799  throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
1800  }
1801 
1802  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1803  const unsigned int wIndex = dimensionIndices.GetWidthIndex();
1804  const unsigned int hIndex = dimensionIndices.GetHeightIndex();
1805  const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
1806 
1807  const TensorShape& inputShape = inputTensorInfo.GetShape();
1808  if (inputShape[hIndex] % m_Parameters.m_BlockSize != 0 || inputShape[wIndex] % m_Parameters.m_BlockSize != 0)
1809  {
1810  throw InvalidArgumentException(descriptorName + ": Input shape must be divisible "
1811  "by block size in all spatial dimensions");
1812  }
1813 
1814  const TensorShape& outputShape = outputTensorInfo.GetShape();
1815  if (outputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
1816  {
1817  throw InvalidArgumentException(descriptorName + ": The depth of the output tensor"
1818  "must be divisible by the square of block size." );
1819  }
1820 }
1821 
1822 void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1823 {
1824  const std::string descriptorName{"FloorQueueDescriptor"};
1825 
1826  ValidateNumInputs(workloadInfo, descriptorName, 1);
1827  ValidateNumOutputs(workloadInfo, descriptorName, 1);
1828 
1829  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1830  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1831 
1832  std::vector<DataType> supportedTypes =
1833  {
1838  };
1839 
1840  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1841 
1842  if (inputTensorInfo != outputTensorInfo)
1843  {
1844  throw InvalidArgumentException(descriptorName + ": Input and output tensor infos do not match.");
1845  }
1846 }
1847 
1848 void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1849 {
1850  // ported from android/ml/nn/common/operations/LSTM.cpp CheckInputTensorDimensions()
1851 
1852  const std::string descriptorName{"LstmQueueDescriptor"};
1853 
1854  // check dimensions of all inputs and outputs
1855  if (workloadInfo.m_InputTensorInfos.size() != 3)
1856  {
1857  throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
1858  }
1859  if (workloadInfo.m_OutputTensorInfos.size() != 4)
1860  {
1861  throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
1862  }
1863 
1864  std::vector<DataType> supportedTypes =
1865  {
1870  };
1871 
1872  // check for supported type of one input and match them with all the other input and output
1873  ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
1874 
1875  // type matches all other inputs
1876  for (uint32_t i = 1u; i < workloadInfo.m_InputTensorInfos.size(); ++i)
1877  {
1878  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1879  workloadInfo.m_InputTensorInfos[i],
1880  descriptorName,
1881  "input_0",
1882  "input_" + std::to_string(i));
1883  }
1884  // type matches all other outputs
1885  for (uint32_t i = 0u; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
1886  {
1887  ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1888  workloadInfo.m_OutputTensorInfos[i],
1889  "LstmQueueDescriptor",
1890  "input_0",
1891  "output_" + std::to_string(i));
1892  }
1893 
1894  // Making sure clipping parameters have valid values.
1895  // == 0 means no clipping
1896  // > 0 means clipping
1897  if (m_Parameters.m_ClippingThresCell < 0.0f)
1898  {
1899  throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
1900  }
1901  if (m_Parameters.m_ClippingThresProj < 0.0f)
1902  {
1903  throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
1904  }
1905 
1906 
1907  // Inferring batch size, number of outputs and number of cells from the inputs.
1908  const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[1];
1909  const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
1910  ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
1911  const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
1912  ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
1913  const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
1914 
1915  // input tensor
1916  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 2, (n_batch * n_input),
1917  descriptorName + " input_0");
1918  // outputStateInTensor
1919  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
1920  descriptorName + " input_1");
1921  // outputStateInTensor
1922  ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
1923  descriptorName + " input_2");
1924  // scratchBufferTensor
1925  unsigned int scratchBufferSize = m_Parameters.m_CifgEnabled ? n_cell * 3 : n_cell * 4;
1926  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[0], 2, (n_batch * scratchBufferSize),
1927  descriptorName + " output_0");
1928  // outputStateOutTensor
1929  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[1], 2, (n_batch * n_output),
1930  descriptorName + " output_1");
1931  // cellStateOutTensor
1932  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 2, (n_batch * n_cell),
1933  descriptorName + " output_2");
1934  // outputTensor
1935  ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[3], 2, (n_batch * n_output),
1936  descriptorName + " output_3");
1937 
1938 
1939  // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
1940  if ( m_InputToInputWeights )
1941  {
1942  ValidateTensorNumDimNumElem(m_InputToInputWeights->GetTensorInfo(), 2,
1943  (n_cell * n_input), "InputLayerNormWeights");
1944  }
1945 
1946  ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
1947  ValidateTensorNumDimNumElem(m_InputToForgetWeights->GetTensorInfo(), 2,
1948  (n_cell * n_input), "InputToForgetWeights");
1949 
1950  ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
1951  ValidateTensorNumDimNumElem(m_InputToCellWeights->GetTensorInfo(), 2,
1952  (n_cell * n_input), "InputToCellWeights");
1953 
1954  if ( m_RecurrentToInputWeights )
1955  {
1956  ValidateTensorNumDimNumElem(m_RecurrentToInputWeights->GetTensorInfo(), 2,
1957  (n_cell * n_output), "RecurrentToInputWeights");
1958  }
1959 
1960  ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
1961  ValidateTensorNumDimNumElem(m_RecurrentToForgetWeights->GetTensorInfo(), 2,
1962  (n_cell * n_output), "RecurrentToForgetWeights");
1963 
1964  ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
1965  ValidateTensorNumDimNumElem(m_RecurrentToCellWeights->GetTensorInfo(), 2,
1966  (n_cell * n_output), "RecurrentToCellWeights");
1967 
1968  // Make sure the input-gate's parameters are either both present (regular
1969  // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
1970  bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
1971  !m_Parameters.m_CifgEnabled) ||
1972  (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
1973  m_Parameters.m_CifgEnabled));
1974  if (!cifg_weights_all_or_none)
1975  {
1976  throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
1977  "RecurrentToInputWeights must either both be present (regular LSTM) "
1978  "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
1979  "accordingly.");
1980  }
1981 
1982  if ( m_CellToInputWeights )
1983  {
1984  ValidateTensorNumDimNumElem(m_CellToInputWeights->GetTensorInfo(), 1,
1985  n_cell, "CellToInputWeights");
1986  }
1987  if ( m_CellToForgetWeights )
1988  {
1989  ValidateTensorNumDimNumElem(m_CellToForgetWeights->GetTensorInfo(), 1,
1990  n_cell, "CellToForgetWeights");
1991  }
1992  if ( m_CellToOutputWeights )
1993  {
1994  ValidateTensorNumDimNumElem(m_CellToOutputWeights->GetTensorInfo(), 1,
1995  n_cell, "CellToOutputWeights");
1996  }
1997 
1998  // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
1999  bool peephole_weights_all_or_none =
2000  (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
2001  && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
2002  || ( !m_CellToInputWeights && !m_CellToForgetWeights
2003  && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
2004  if (!peephole_weights_all_or_none)
2005  {
2006  throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
2007  }
2008 
2009  // Make sure the input gate bias is present only when not a CIFG-LSTM.
2010  if (m_Parameters.m_CifgEnabled)
2011  {
2012  if (m_InputGateBias)
2013  {
2014  throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
2015  }
2016  }
2017  else
2018  {
2019  if (!m_InputGateBias)
2020  {
2021  throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
2022  "must be present.");
2023  }
2024  ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1,
2025  n_cell, "InputGateBias");
2026  }
2027 
2028  ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
2029  ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
2030 
2031  ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
2032  ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
2033 
2034  ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
2035  ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
2036 
2037  if (m_ProjectionWeights)
2038  {
2039  ValidateTensorNumDimNumElem(m_ProjectionWeights->GetTensorInfo(), 2,
2040  (n_cell * n_output), "ProjectionWeights");
2041  }
2042  if (m_ProjectionBias)
2043  {
2044  ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
2045  }
2046 
2047  // Making sure the projection tensors are consistent:
2048  // 1) If projection weight is not present, then projection bias should not be
2049  // present.
2050  // 2) If projection weight is present, then projection bias is optional.
2051  bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
2052  !m_Parameters.m_ProjectionEnabled)
2053  || (m_ProjectionWeights && !m_ProjectionBias &&
2054  m_Parameters.m_ProjectionEnabled)
2055  || (m_ProjectionWeights && m_ProjectionBias &&
2056  m_Parameters.m_ProjectionEnabled));
2057  if (!projecton_tensors_consistent)
2058  {
2059  throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
2060  }
2061 
2062  // The four layer normalization weights either all have values or none of them have values. Additionally, if
2063  // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
2064  // either all have values or none of them have values. Layer normalization is used when the values of all the
2065  // layer normalization weights are present
2066  if (m_InputLayerNormWeights)
2067  {
2068  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
2069  }
2070  if (m_ForgetLayerNormWeights)
2071  {
2072  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2073  }
2074  if (m_CellLayerNormWeights)
2075  {
2076  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2077  }
2078  if (m_OutputLayerNormWeights)
2079  {
2080  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2081  }
2082 
2083  if (m_Parameters.m_LayerNormEnabled)
2084  {
2085  if (!m_Parameters.m_CifgEnabled)
2086  {
2087  if (!m_InputLayerNormWeights)
2088  {
2089  throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
2090  "disabled but InputLayerNormWeights are not present");
2091  }
2092  ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(),
2093  1, n_cell, "InputLayerNormWeights");
2094  }
2095  else if (m_InputLayerNormWeights)
2096  {
2097  throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
2098  "enabled");
2099  }
2100 
2101  ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
2102  "ForgetLayerNormWeights");
2103  ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2104 
2105  ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
2106  "OutputLayerNormWeights");
2107  ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2108 
2109  ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
2110  "CellLayerNormWeights");
2111  ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2112  }
2113  else if (m_InputLayerNormWeights || m_ForgetLayerNormWeights || m_OutputLayerNormWeights || m_CellLayerNormWeights)
2114  {
2115  throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
2116  "normalisation weights are present.");
2117  }
2118 }
2119 
2121 {
2122  const std::string descriptorName{"ConvertBf16ToFp32QueueDescriptor"};
2123 
2124  ValidateNumInputs(workloadInfo, descriptorName, 1);
2125  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2126 
2127  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2128  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2129 
2130  if (inputTensorInfo.GetDataType() != DataType::BFloat16)
2131  {
2132  throw InvalidArgumentException(descriptorName + ": Input tensor type must be BFloat16.");
2133  }
2134 
2135  if (outputTensorInfo.GetDataType() != DataType::Float32)
2136  {
2137  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32.");
2138  }
2139 
2140  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2141 }
2142 
2144 {
2145  const std::string descriptorName{"ConvertFp32ToBf16QueueDescriptor"};
2146 
2147  ValidateNumInputs(workloadInfo, descriptorName, 1);
2148  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2149 
2150  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2151  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2152 
2153  if (inputTensorInfo.GetDataType() != DataType::Float32)
2154  {
2155  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32.");
2156  }
2157 
2158  if (outputTensorInfo.GetDataType() != DataType::BFloat16)
2159  {
2160  throw InvalidArgumentException(descriptorName + ": Output tensor type must be BFloat16.");
2161  }
2162 
2163  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2164 }
2165 
2167 {
2168  const std::string descriptorName{"ConvertFp32ToFp16QueueDescriptor"};
2169 
2170  ValidateNumInputs(workloadInfo, descriptorName, 1);
2171  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2172 
2173  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2174  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2175 
2176  if (inputTensorInfo.GetDataType() != DataType::Float32)
2177  {
2178  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32.");
2179  }
2180 
2181  if (outputTensorInfo.GetDataType() != DataType::Float16)
2182  {
2183  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float16.");
2184  }
2185 
2186  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2187 }
2188 
2190 {
2191  const std::string descriptorName{"ConvertFp16ToFp32QueueDescriptor"};
2192 
2193  ValidateNumInputs(workloadInfo, descriptorName, 1);
2194  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2195 
2196  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2197  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2198 
2199  if (inputTensorInfo.GetDataType() != DataType::Float16)
2200  {
2201  throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float16.");
2202  }
2203 
2204  if (outputTensorInfo.GetDataType() != DataType::Float32)
2205  {
2206  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32.");
2207  }
2208 
2209  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2210 }
2211 
2212 void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2213 {
2214  const std::string descriptorName{"DivisionQueueDescriptor"};
2215 
2216  ValidateNumInputs(workloadInfo, descriptorName, 2);
2217  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2218 
2219  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2220  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2221  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2222 
2223  std::vector<DataType> supportedTypes =
2224  {
2232  };
2233 
2234  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2235  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2236  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2237 
2238  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2239  inputTensorInfo1,
2240  outputTensorInfo,
2241  descriptorName,
2242  "input_0",
2243  "input_1");
2244 }
2245 
2247 {
2248  const std::string descriptorName{"SubtractionQueueDescriptor"};
2249 
2250  ValidateNumInputs(workloadInfo, descriptorName, 2);
2251  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2252 
2253  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2254  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2255  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2256 
2257  std::vector<DataType> supportedTypes =
2258  {
2266  };
2267 
2268  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2269  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2270  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2271 
2272  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2273  inputTensorInfo1,
2274  outputTensorInfo,
2275  descriptorName,
2276  "input_0",
2277  "input_1");
2278 }
2279 
2280 void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2281 {
2282  const std::string descriptorName{"MaximumQueueDescriptor"};
2283 
2284  ValidateNumInputs(workloadInfo, descriptorName, 2);
2285  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2286 
2287  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2288  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2289  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2290 
2291  std::vector<DataType> supportedTypes =
2292  {
2300  };
2301 
2302  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2303  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2304  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2305 
2306  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2307  inputTensorInfo1,
2308  outputTensorInfo,
2309  descriptorName,
2310  "input_0",
2311  "input_1");
2312 }
2313 
2314 void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2315 {
2316  const std::string descriptorName{"MeanQueueDescriptor"};
2317 
2318  ValidateNumInputs(workloadInfo, descriptorName, 1);
2319  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2320 
2321  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2322  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2323 
2324  std::vector<DataType> supportedTypes =
2325  {
2332  };
2333 
2334  // First check if input tensor data type is supported, then
2335  // check if this data type matches the output tensor data type
2336  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2337  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2338 
2339  if (m_Parameters.m_KeepDims)
2340  {
2341  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2342  }
2343  else if (m_Parameters.m_Axis.empty())
2344  {
2345  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
2346  }
2347  else
2348  {
2349  unsigned int outputDim =
2350  inputTensorInfo.GetNumDimensions() - armnn::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
2351  ValidateTensorNumDimensions(outputTensorInfo,
2352  descriptorName,
2353  outputDim > 0 ? outputDim : 1,
2354  "output");
2355  }
2356 }
2357 
2358 void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2359 {
2360  const std::string descriptorName{"PadQueueDescriptor"};
2361 
2362  ValidateNumInputs(workloadInfo, descriptorName, 1);
2363  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2364 
2365  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2366  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2367 
2368  // input and output should have the same number of dimensions
2369  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2370 
2371  // there should be entry in the pad list for each dimension in the input tensor
2372  if (m_Parameters.m_PadList.size() != inputTensorInfo.GetNumDimensions()) {
2373  throw InvalidArgumentException(descriptorName + ":Pad List should contain the same number of entries "
2374  "as there are dimensions in the input tensor that is " +
2375  std::to_string(inputTensorInfo.GetNumDimensions()) + " entries " +
2376  " not " + std::to_string(m_Parameters.m_PadList.size()) + " entries.");
2377  }
2378 }
2379 
2380 void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2381 {
2382  const std::string descriptorName{"QuantizeQueueDescriptor"};
2383 
2384  ValidateNumInputs(workloadInfo, descriptorName, 1);
2385  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2386 
2387  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2388  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2389 
2390  std::vector<DataType> supportedTypes =
2391  {
2399  };
2400 
2401  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2402 
2403  if (!IsQuantizedType(outputTensorInfo.GetDataType()))
2404  {
2405  throw InvalidArgumentException(descriptorName + ": Output of quantized layer must be quantized type.");
2406  }
2407 }
2408 
2410 {
2411  const std::string descriptorName{"BatchToSpaceNdQueueDescriptor"};
2412 
2413  ValidateNumInputs(workloadInfo, descriptorName, 1);
2414  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2415 
2416  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2417  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2418 
2419  std::vector<DataType> supportedTypes =
2420  {
2427  };
2428 
2429  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2430  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2431 }
2432 
2434 {
2435  const std::string descriptorName{"StridedSliceQueueDescriptor"};
2436 
2437  ValidateNumInputs(workloadInfo, descriptorName, 1);
2438  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2439 
2440  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2441  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2442 
2443  std::vector<DataType> supportedTypes =
2444  {
2451  };
2452 
2453  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2454  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2455 
2456  ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2457 
2458  const uint32_t rank = inputTensorInfo.GetNumDimensions();
2459  if (rank > 4)
2460  {
2461  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
2462  }
2463 
2464  // Begin, End & Stride length must be of rank(input0)
2465  if (m_Parameters.m_Begin.size() != rank)
2466  {
2467  throw InvalidArgumentException(descriptorName + ": Begin length must be of rank " + std::to_string(rank));
2468  }
2469 
2470  if (m_Parameters.m_End.size() != rank)
2471  {
2472  throw InvalidArgumentException(descriptorName + ": End length must be of rank " + std::to_string(rank));
2473  }
2474 
2475  if (m_Parameters.m_Stride.size() != rank)
2476  {
2477  throw InvalidArgumentException(descriptorName + ": Stride length must be of rank " + std::to_string(rank));
2478  }
2479 
2480  // Stride entries must be non-zero
2481  for (auto& stride : m_Parameters.m_Stride)
2482  {
2483  if (stride == 0)
2484  {
2485  throw InvalidArgumentException(descriptorName + ": Stride entries must be non-zero.");
2486  }
2487  }
2488 }
2489 
2490 void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2491 {
2492  const std::string descriptorName{"MinimumQueueDescriptor"};
2493 
2494  ValidateNumInputs(workloadInfo, descriptorName, 2);
2495  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2496 
2497  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2498  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2499  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2500 
2501  std::vector<DataType> supportedTypes =
2502  {
2510  };
2511 
2512  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2513  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2514  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2515 
2516  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2517  inputTensorInfo1,
2518  outputTensorInfo,
2519  descriptorName,
2520  "input_0",
2521  "input_1");
2522 }
2523 
2524 void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2525 {
2526  const std::string descriptorName{"DebugQueueDescriptor"};
2527 
2528  ValidateNumInputs(workloadInfo, descriptorName, 1);
2529  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2530 }
2531 
2532 void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2533 {
2534  const std::string descriptorName{"EqualQueueDescriptor"};
2535 
2536  ValidateNumInputs(workloadInfo, descriptorName, 2);
2537  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2538 
2539  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2540  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2541  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2542 
2543  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2544  inputTensorInfo1,
2545  outputTensorInfo,
2546  descriptorName,
2547  "input_0",
2548  "input_1");
2549 
2550  if (outputTensorInfo.GetDataType() != DataType::Boolean)
2551  {
2552  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2553  }
2554 }
2555 
2556 void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2557 {
2558  const std::string descriptorName{"GreaterQueueDescriptor"};
2559 
2560  ValidateNumInputs(workloadInfo, descriptorName, 2);
2561  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2562 
2563  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2564  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2565  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2566 
2567  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2568  inputTensorInfo1,
2569  outputTensorInfo,
2570  descriptorName,
2571  "input_0",
2572  "input_1");
2573 
2574  if (outputTensorInfo.GetDataType() != DataType::Boolean)
2575  {
2576  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2577  }
2578 }
2579 
2580 void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2581 {
2582  const std::string descriptorName{"RsqrtQueueDescriptor"};
2583 
2584  ValidateNumInputs(workloadInfo, descriptorName, 1);
2585  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2586 
2587  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2588  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2589 
2590  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2591 
2592  std::vector<DataType> supportedTypes =
2593  {
2600  };
2601 
2602  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2603  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2604 }
2605 
2606 void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2607 {
2608  const std::string descriptorName{"GatherQueueDescriptor"};
2609 
2610  ValidateNumInputs(workloadInfo, descriptorName, 2);
2611  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2612 
2613  const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1];
2614  if (indicesTensorInfo.GetDataType() != DataType::Signed32)
2615  {
2616  throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32.");
2617  }
2618 
2619  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2620  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2621 
2622  std::vector<DataType> supportedTypes =
2623  {
2631  };
2632 
2633  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2634 
2635  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2636 
2637  unsigned int outputDim = inputTensorInfo.GetNumDimensions() + indicesTensorInfo.GetNumDimensions() - 1;
2638  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output");
2639 }
2640 
2642 {
2643  const std::string& descriptorName{"DetectionPostProcessQueueDescriptor"};
2644 
2645  ValidateNumInputs(workloadInfo, descriptorName, 2);
2646 
2647  if (workloadInfo.m_OutputTensorInfos.size() != 4)
2648  {
2649  throw InvalidArgumentException(descriptorName + ": Requires exactly four outputs. " +
2650  to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
2651  }
2652 
2653  if (m_Anchors == nullptr)
2654  {
2655  throw InvalidArgumentException(descriptorName + ": Anchors tensor descriptor is missing.");
2656  }
2657 
2658  const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
2659  const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
2660  const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
2661 
2662  const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
2663  const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
2664  const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
2665  const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
2666 
2667  ValidateTensorNumDimensions(boxEncodingsInfo, descriptorName, 3, "box encodings");
2668  ValidateTensorNumDimensions(scoresInfo, descriptorName, 3, "scores");
2669  ValidateTensorNumDimensions(anchorsInfo, descriptorName, 2, "anchors");
2670 
2671  const std::vector<DataType> supportedInputTypes =
2672  {
2679  };
2680 
2681  ValidateDataTypes(boxEncodingsInfo, supportedInputTypes, descriptorName);
2682  ValidateDataTypes(scoresInfo, supportedInputTypes, descriptorName);
2683  ValidateDataTypes(anchorsInfo, supportedInputTypes, descriptorName);
2684 
2685  ValidateTensorNumDimensions(detectionBoxesInfo, descriptorName, 3, "detection boxes");
2686  ValidateTensorNumDimensions(detectionScoresInfo, descriptorName, 2, "detection scores");
2687  ValidateTensorNumDimensions(detectionClassesInfo, descriptorName, 2, "detection classes");
2688  ValidateTensorNumDimensions(numDetectionsInfo, descriptorName, 1, "num detections");
2689 
2690  // NOTE: Output is always Float32 regardless of input type
2691  ValidateTensorDataType(detectionBoxesInfo, DataType::Float32, descriptorName, "detection boxes");
2692  ValidateTensorDataType(detectionScoresInfo, DataType::Float32, descriptorName, "detection scores");
2693  ValidateTensorDataType(detectionClassesInfo, DataType::Float32, descriptorName, "detection classes");
2694  ValidateTensorDataType(numDetectionsInfo, DataType::Float32, descriptorName, "num detections");
2695 
2696  if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f)
2697  {
2698  throw InvalidArgumentException(descriptorName + ": Intersection over union threshold "
2699  "must be positive and less than or equal to 1.");
2700  }
2701 
2702  if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
2703  {
2704  throw InvalidArgumentException(descriptorName + ": Number of classes with background "
2705  "should be equal to number of classes + 1.");
2706  }
2707 }
2708 
2709 void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2710 {
2711  const std::string& descriptorName{"DequantizeQueueDescriptor"};
2712 
2713  ValidateNumInputs(workloadInfo, descriptorName, 1);
2714  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2715 
2716  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2717  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2718 
2719  if (!IsQuantizedType(inputTensorInfo.GetDataType()))
2720  {
2721  throw InvalidArgumentException(descriptorName + ": Input to dequantize layer must be quantized type.");
2722  }
2723 
2724  std::vector<DataType> supportedTypes =
2725  {
2729  };
2730 
2731  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2732 }
2733 
2734 void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2735 {
2736  const std::string& descriptorName{"MergeQueueDescriptor"};
2737 
2738  ValidateNumInputs(workloadInfo, descriptorName, 2);
2739  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2740 
2741  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2742  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2743  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2744 
2745  ValidateTensorShapesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2746  ValidateTensorShapesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2747 
2748  ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2749  ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2750 }
2751 
2752 void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2753 {
2754  const std::string& descriptorName{"SwitchQueueDescriptor"};
2755 
2756  ValidateNumInputs(workloadInfo, descriptorName, 2);
2757  ValidateNumOutputs(workloadInfo, descriptorName, 2);
2758 
2759  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2760  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2761 
2762  const TensorInfo& outputTensorInfo0 = workloadInfo.m_OutputTensorInfos[0];
2763  const TensorInfo& outputTensorInfo1 = workloadInfo.m_OutputTensorInfos[1];
2764 
2765  std::vector<DataType> supportedTypes =
2766  {
2772  };
2773 
2774  ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2775  ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2776 
2777  ValidateDataTypes(outputTensorInfo0, supportedTypes, descriptorName);
2778  ValidateDataTypes(outputTensorInfo1, supportedTypes, descriptorName);
2779 
2780  ValidateTensorShapesMatch(inputTensorInfo0,
2781  outputTensorInfo0,
2782  descriptorName,
2783  "input_0",
2784  "output_0");
2785 
2786  ValidateTensorShapesMatch(inputTensorInfo0,
2787  outputTensorInfo1,
2788  descriptorName,
2789  "input_0",
2790  "output_1");
2791 }
2792 
2793 void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& /*workloadInfo*/) const
2794 {
2795  // This is internally generated so it should not need validation.
2796 }
2797 
2798 void PreluQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2799 {
2800  const std::string& descriptorName{"PreluQueueDescriptor"};
2801 
2802  ValidateNumInputs(workloadInfo, descriptorName, 2);
2803  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2804 
2805  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2806  const TensorInfo& alphaTensorInfo = workloadInfo.m_InputTensorInfos[1];
2807  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2808 
2809  std::vector<DataType> supportedTypes
2810  {
2817  };
2818 
2819  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2820  ValidateDataTypes(alphaTensorInfo, supportedTypes, descriptorName);
2821 
2822  ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2823 
2824  ValidateTensorDataTypesMatch(inputTensorInfo, alphaTensorInfo, descriptorName, "input", "alpha");
2825  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "ouptut");
2826 
2827  ValidateBroadcastTensorShapesMatch(inputTensorInfo,
2828  alphaTensorInfo,
2829  outputTensorInfo,
2830  descriptorName,
2831  "input",
2832  "alpha");
2833 }
2834 
2836 {
2837  const std::string descriptorName{"TransposeConvolution2dQueueDescriptor"};
2838 
2839  ValidateNumInputs(workloadInfo, descriptorName, 1);
2840  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2841 
2842  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2843  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2844 
2845  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
2846  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
2847 
2848  ValidatePointer(m_Weight, descriptorName, "weight");
2849 
2850  const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
2851  ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
2852 
2853  ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
2854 
2855  Optional<TensorInfo> optionalBiasTensorInfo;
2856  if (m_Parameters.m_BiasEnabled)
2857  {
2858  ValidatePointer(m_Bias, descriptorName, "bias");
2859 
2860  optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
2861  const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
2862 
2863  ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
2864  ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName);
2865  }
2866 
2867  ValidatePerAxisQuantization(inputTensorInfo,
2868  outputTensorInfo,
2869  weightTensorInfo,
2870  optionalBiasTensorInfo,
2871  descriptorName);
2872 
2873  std::vector<DataType> supportedTypes =
2874  {
2881  };
2882 
2883  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2884  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2885 }
2886 
2887 void TransposeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2888 {
2889  const std::string descriptorName{"TransposeQueueDescriptor"};
2890 
2891  ValidateNumInputs(workloadInfo, descriptorName, 1);
2892  ValidateNumOutputs(workloadInfo, descriptorName, 1);
2893 
2894  const PermutationVector& mapping = m_Parameters.m_DimMappings;
2895 
2896  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2897  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2898 
2899  ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
2900  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
2901 
2902  for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
2903  {
2904  if (inputTensorInfo.GetShape()[mapping[i]] != outputTensorInfo.GetShape()[i])
2905  {
2906  throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(mapping[i]) +
2907  " (=" + to_string(inputTensorInfo.GetShape()[mapping[i]]) + ") " +
2908  "must match dst dimension " + to_string(i) +
2909  " (=" + to_string(outputTensorInfo.GetShape()[i]) + ")");
2910  }
2911  }
2912 
2913  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2914 }
2915 
2916 void QLstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2917 {
2918  const std::string descriptorName{"QLstmQueueDescriptor"};
2919 
2920  // Validate number of inputs/outputs
2921  ValidateNumInputs(workloadInfo, descriptorName, 3);
2922  ValidateNumOutputs(workloadInfo, descriptorName, 3);
2923 
2924  // Input/output tensor info
2925  auto inputInfo = workloadInfo.m_InputTensorInfos[0];
2926  auto outputStateInInfo = workloadInfo.m_InputTensorInfos[1];
2927  auto cellStateInInfo = workloadInfo.m_InputTensorInfos[2];
2928 
2929  auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
2930  auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
2931  auto outputInfo = workloadInfo.m_OutputTensorInfos[2];
2932 
2933  // Supported types for various tensors in QLSTM
2934  std::vector<DataType> inputOutputSupportedTypes =
2935  {
2937  };
2938 
2939  std::vector<DataType> cellStateSupportedTypes =
2940  {
2942  };
2943 
2944  std::vector<DataType> weightsSupportedTypes =
2945  {
2947  };
2948 
2949  std::vector<DataType> layerNormPeepholeWeightsSupportedTypes =
2950  {
2952  };
2953 
2954  std::vector<DataType> biasSupportedTypes =
2955  {
2957  };
2958 
2959  // Validate types of input/output tensors
2960  ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
2961  ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
2962  ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
2963 
2964  ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
2965  ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
2966  ValidateDataTypes(outputInfo, inputOutputSupportedTypes, descriptorName);
2967 
2968  // Validate matching types of input/output tensors
2969  ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
2970  ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
2971  "outputStateIn", "outputStateOut");
2972  ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
2973 
2974  // Infer number of batches, number of units, input size and output size from tensor dimensions
2975  const uint32_t numBatches = inputInfo.GetShape()[0];
2976  const uint32_t inputSize = inputInfo.GetShape()[1];
2977  const uint32_t outputSize = outputStateInInfo.GetShape()[1];
2978  const uint32_t numUnits = cellStateInInfo.GetShape()[1];
2979 
2980  // Validate number of dimensions and number of elements for input/output tensors
2981  ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
2982  ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
2983  ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * numUnits), descriptorName + " cellStateIn");
2984 
2985  ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
2986  ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * numUnits), descriptorName + " cellStateOut");
2987  ValidateTensorNumDimNumElem(outputInfo, 2, (numBatches * outputSize), descriptorName + " output");
2988 
2989  // Validate number of dimensions and number of elements for MANDATORY weight tensors
2990  ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
2991  auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
2992  ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (numUnits * inputSize), " InputToForgetWeights");
2993 
2994  ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
2995  auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
2996  ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (numUnits * inputSize), " InputToCellWeights");
2997 
2998  ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
2999  auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3000  ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (numUnits * inputSize), " InputToOutputWeights");
3001 
3002  ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3003  auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3004  ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (numUnits * outputSize),
3005  " RecurrentToForgetWeights");
3006 
3007  ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3008  auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3009  ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3010 
3011  ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3012  auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3013  ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3014 
3015  // Validate data types for MANDATORY weights tensors (all should match each other)
3016  ValidateDataTypes(inputToForgetWeightsInfo, weightsSupportedTypes, descriptorName);
3017 
3018  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToCellWeightsInfo, descriptorName,
3019  "inputToForgetWeights", "inputToCellWeights");
3020  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3021  "inputToForgetWeights", "inputToOutputWeights");
3022 
3023  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3024  "inputToForgetWeights", "recurrentToForgeteights");
3025  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3026  "inputToForgetWeights", "recurrentToCellWeights");
3027  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3028  "inputToForgetWeights", "recurrentToOutputWeights");
3029 
3030  // Validate number of dimensions and number of elements for MANDATORY bias tensors
3031  ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3032  auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3033  ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, numUnits, " ForgetGateBias");
3034 
3035  ValidatePointer(m_CellBias, descriptorName, "CellBias");
3036  auto cellBiasInfo = m_CellBias->GetTensorInfo();
3037  ValidateTensorNumDimNumElem(cellBiasInfo, 1, numUnits, " CellBias");
3038 
3039  ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3040  auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3041  ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, numUnits, " OutputGateBias");
3042 
3043  // Validate data types for MANDATORY bias tensors
3044  ValidateDataTypes(forgetGateBiasInfo, biasSupportedTypes, descriptorName);
3045 
3046  ValidateTensorDataTypesMatch(forgetGateBiasInfo, cellBiasInfo, descriptorName,
3047  "forgetGateBias", "cellBias");
3048  ValidateTensorDataTypesMatch(forgetGateBiasInfo, outputGateBiasInfo, descriptorName,
3049  "forgetGateBias", "outputGateBias");
3050 
3051  // Validate OPTIONAL params: CIFG (inputToInputWeights, recurrentToInputWeights, inputGateBias)
3052  const bool allCifgParamsPresentOrNot = ((m_InputToInputWeights && m_RecurrentToInputWeights && m_InputGateBias &&
3053  !m_Parameters.m_CifgEnabled) ||
3054  (!m_InputToInputWeights && !m_RecurrentToInputWeights &&
3055  !m_InputGateBias && m_Parameters.m_CifgEnabled));
3056 
3057  if (!allCifgParamsPresentOrNot)
3058  {
3059  throw InvalidArgumentException(descriptorName +
3060  ": InputToInputWeights, RecurrentToInputWeights and InputGateBias must either all be present "
3061  "(CIFG disabled) or not be present at all (CIFG enabled). m_Parameters.m_CifgEnabled should be "
3062  "set appropriately.");
3063  }
3064 
3065  if (!m_Parameters.m_CifgEnabled)
3066  {
3067  // Validate number of dimensions and number of elements
3068  auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3069  ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (numUnits * inputSize), " InputToInputWeights");
3070 
3071  auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3072  ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (numUnits * outputSize),
3073  " RecurrentToInputWeights");
3074 
3075  auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3076  ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, numUnits, " InputGateBias");
3077 
3078  // Validate data types
3079  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToInputWeightsInfo, descriptorName,
3080  "inputToForgetWeights", "inputToInputWeights");
3081  ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3082  "inputToForgetWeights", "recurrentToInputWeights");
3083  ValidateTensorDataTypesMatch(forgetGateBiasInfo, inputGateBiasInfo, descriptorName,
3084  "forgetGateBias", "inputGateBias");
3085  }
3086 
3087  // Validate OPTIONAL params: Peephole (cellToInputWeights, cellToForgetWeights, cellToOutputWeights)
3088  bool allPeepholeWeightsPresentOrNot =
3089  (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights
3090  && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
3091  || (!m_CellToInputWeights && !m_CellToForgetWeights
3092  && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
3093 
3094  if (!allPeepholeWeightsPresentOrNot)
3095  {
3096  throw InvalidArgumentException(descriptorName +
3097  ": CellToInputWeights, CellToForgetWeights and CellToOutputWeights should all be present (Peephole "
3098  "enabled) or not be present at all (Peephole disabled). CellToInputWeights should only be present "
3099  "when Peephole is enabled and CIFG is disabled. m_Parameters.m_PeepholeEnabled should be set "
3100  "appropriately.");
3101  }
3102 
3103  if (m_Parameters.m_PeepholeEnabled)
3104  {
3105  auto cellToForgetWeightsInfo = m_CellToForgetWeights->GetTensorInfo();
3106  ValidateTensorNumDimNumElem(cellToForgetWeightsInfo, 1, numUnits, " cellToForgetWeights");
3107  ValidateDataTypes(cellToForgetWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3108 
3109  auto cellToOutputWeightsInfo = m_CellToOutputWeights->GetTensorInfo();
3110  ValidateTensorNumDimNumElem(cellToOutputWeightsInfo, 1, numUnits, " cellToOutputWeights");
3111  ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToOutputWeightsInfo, descriptorName,
3112  "cellToForgetWeight", "cellToOutputWeights");
3113 
3114  if (!m_Parameters.m_CifgEnabled)
3115  {
3116  auto cellToInputWeightsInfo = m_CellToInputWeights->GetTensorInfo();
3117  ValidateTensorNumDimNumElem(cellToInputWeightsInfo, 1, numUnits, " cellToInputWeights");
3118  ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToInputWeightsInfo, descriptorName,
3119  "cellToForgetWeights", "cellToInputWeights");
3120  }
3121  }
3122 
3123  // Validate OPTIONAL params: Layer Norm Weights
3124  bool allLayerNormWeightsPresentOrNot =
3125  (((m_InputLayerNormWeights || m_Parameters.m_CifgEnabled) && m_ForgetLayerNormWeights
3126  && m_CellLayerNormWeights && m_OutputLayerNormWeights && m_Parameters.m_LayerNormEnabled)
3127  || (!m_InputLayerNormWeights && !m_ForgetLayerNormWeights && !m_CellLayerNormWeights
3128  && !m_OutputLayerNormWeights && !m_Parameters.m_LayerNormEnabled));
3129 
3130  if (!allLayerNormWeightsPresentOrNot)
3131  {
3132  throw InvalidArgumentException(descriptorName +
3133  ": InputLayerNormWeights, ForgetLayerNormWeights, m_OutputLayerNormWeights "
3134  "and CellLayerNormWeights should all be present (Layer Norm enabled) or not "
3135  "be present at all (Layer Norm disabled). InputLayerNormWeights should "
3136  "only be present when Layer Norm is enabled and CIFG is disabled. "
3137  "m_Parameters.m_LayerNormEnabled should be set appropriately.");
3138  }
3139 
3140  if (m_Parameters.m_LayerNormEnabled)
3141  {
3142  auto forgetLayerNormWeightsInfo = m_ForgetLayerNormWeights->GetTensorInfo();
3143  ValidateTensorNumDimNumElem(forgetLayerNormWeightsInfo, 1, numUnits, " forgetLayerNormWeights");
3144  ValidateDataTypes(forgetLayerNormWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3145 
3146  auto cellLayerNormWeightsInfo = m_CellLayerNormWeights->GetTensorInfo();
3147  ValidateTensorNumDimNumElem(cellLayerNormWeightsInfo, 1, numUnits, " cellLayerNormWeights");
3148  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, cellLayerNormWeightsInfo, descriptorName,
3149  "forgetLayerNormWeights", "cellLayerNormWeights");
3150 
3151  auto outputLayerNormWeightsInfo = m_OutputLayerNormWeights->GetTensorInfo();
3152  ValidateTensorNumDimNumElem(outputLayerNormWeightsInfo, 1, numUnits, " outputLayerNormWeights");
3153  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, outputLayerNormWeightsInfo, descriptorName,
3154  "forgetLayerNormWeights", "outputLayerNormWeights");
3155 
3156  if (!m_Parameters.m_CifgEnabled)
3157  {
3158  auto inputLayerNormWeightsInfo = m_InputLayerNormWeights->GetTensorInfo();
3159  ValidateTensorNumDimNumElem(inputLayerNormWeightsInfo, 1, numUnits, " inputLayerNormWeights");
3160  ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, inputLayerNormWeightsInfo, descriptorName,
3161  "forgetLayerNormWeights", "inputLayerNormWeights");
3162  }
3163  }
3164 
3165  // Validate OPTIONAL params: Projection (projectionWeights, projectionBias)
3166  bool correctProjectionTensorsPresent =
3167  ((!m_ProjectionWeights && !m_ProjectionBias && !m_Parameters.m_ProjectionEnabled) ||
3168  (m_ProjectionWeights && !m_ProjectionBias && m_Parameters.m_ProjectionEnabled) ||
3169  (m_ProjectionWeights && m_ProjectionBias && m_Parameters.m_ProjectionEnabled));
3170 
3171  if (!correctProjectionTensorsPresent)
3172  {
3173  throw InvalidArgumentException(descriptorName +
3174  ": If projection is enabled, ProjectionWeights should be present and "
3175  "ProjectionBias is optional. If projection is disabled, neither "
3176  "ProjectionWeights nor ProjectionBias should be present.");
3177  }
3178 
3179  if (m_Parameters.m_ProjectionEnabled)
3180  {
3181  auto projectionWeightsInfo = m_ProjectionWeights->GetTensorInfo();
3182  ValidateTensorNumDimNumElem(projectionWeightsInfo, 2, (numUnits * outputSize), "ProjectionWeights");
3183  ValidateDataTypes(projectionWeightsInfo, weightsSupportedTypes, descriptorName);
3184 
3185  if (m_ProjectionBias)
3186  {
3187  auto projectionBiasInfo = m_ProjectionBias->GetTensorInfo();
3188  ValidateTensorNumDimNumElem(projectionBiasInfo, 1, outputSize, "ProjectionBias");
3189  ValidateDataTypes(projectionBiasInfo, biasSupportedTypes, descriptorName);
3190  }
3191 
3192  }
3193  else if ((outputInfo.GetQuantizationScale() != m_Parameters.m_HiddenStateScale) &&
3194  outputInfo.GetQuantizationOffset() != m_Parameters.m_HiddenStateZeroPoint) {
3195  throw InvalidArgumentException(descriptorName +
3196  ": If projection is disabled, output quantization info (scale, offset) "
3197  "should match HiddenStateScale and HiddenStateZeroPoint.");
3198  }
3199 
3200 }
3201 
3203 {
3204  const std::string descriptorName{"QuantizedLstmQueueDescriptor"};
3205 
3206  // Validate number of inputs/outputs
3207  ValidateNumInputs(workloadInfo, descriptorName, 3);
3208  ValidateNumOutputs(workloadInfo, descriptorName, 2);
3209 
3210  // Input/output tensor infos
3211  auto inputInfo = workloadInfo.m_InputTensorInfos[0];
3212  auto cellStateInInfo = workloadInfo.m_InputTensorInfos[1];
3213  auto outputStateInInfo = workloadInfo.m_InputTensorInfos[2];
3214 
3215  auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
3216  auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
3217 
3218  std::vector<DataType> inputOutputSupportedTypes =
3219  {
3221  };
3222 
3223  std::vector<DataType> cellStateSupportedTypes =
3224  {
3226  };
3227 
3228  std::vector<DataType> weightsSupportedTypes =
3229  {
3231  };
3232 
3233  std::vector<DataType> biasSupportedTypes =
3234  {
3236  };
3237 
3238  // Validate types of input/output tensors
3239  ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3240  ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3241  ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3242 
3243  ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3244  ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3245 
3246  // Validate matching types of input/output tensors
3247  ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3248  ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3249  "outputStateIn", "outputStateOut");
3250  ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3251 
3252  // Validate matching quantization info for input/output tensors
3253  ValidateTensorQuantizationSpace(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3254  ValidateTensorQuantizationSpace(inputInfo, outputStateOutInfo, descriptorName, "input", "outputStateOut");
3255  ValidateTensorQuantizationSpace(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3256 
3257  // Infer number of batches, input size and output size from tensor dimensions
3258  const uint32_t numBatches = inputInfo.GetShape()[0];
3259  const uint32_t inputSize = inputInfo.GetShape()[1];
3260  const uint32_t outputSize = cellStateInInfo.GetShape()[1];
3261 
3262  // Validate number of dimensions and number of elements for input/output tensors
3263  ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3264  ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * outputSize), descriptorName + " cellStateIn");
3265  ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3266  ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * outputSize), descriptorName + " cellStateOut");
3267  ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3268 
3269  // Validate number of dimensions and number of elements for weights tensors
3270  ValidatePointer(m_InputToInputWeights, descriptorName, "InputToInputWeights");
3271  auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3272  ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (outputSize * inputSize), " InputToInputWeights");
3273 
3274  ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3275  auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3276  ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (outputSize * inputSize), " InputToForgetWeights");
3277 
3278  ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3279  auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3280  ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (outputSize * inputSize), " InputToCellWeights");
3281 
3282  ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3283  auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3284  ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (outputSize * inputSize), " InputToOutputWeights");
3285 
3286  ValidatePointer(m_RecurrentToInputWeights, descriptorName, "RecurrentToInputWeights");
3287  auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3288  ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToInputWeights");
3289 
3290  ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3291  auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3292  ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (outputSize * outputSize),
3293  " RecurrentToForgetWeights");
3294 
3295  ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3296  auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3297  ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3298 
3299  ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3300  auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3301  ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3302 
3303  // Validate data types for weights tensors (all should match each other)
3304  ValidateDataTypes(inputToInputWeightsInfo, weightsSupportedTypes, descriptorName);
3305 
3306  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToForgetWeightsInfo, descriptorName,
3307  "inputToInputWeights", "inputToForgetWeights");
3308  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToCellWeightsInfo, descriptorName,
3309  "inputToInputWeights", "inputToCellWeights");
3310  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3311  "inputToInputWeights", "inputToOutputWeights");
3312 
3313  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3314  "inputToInputWeights", "recurrentToInputWeights");
3315  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3316  "inputToInputWeights", "recurrentToForgeteights");
3317  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3318  "inputToInputWeights", "recurrentToCellWeights");
3319  ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3320  "inputToInputWeights", "recurrentToOutputWeights");
3321 
3322  // Validate matching quantization info for weight tensors (all should match each other)
3323  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToForgetWeightsInfo,
3324  descriptorName, "inputToInputWeights", "inputToForgetWeights");
3325  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToCellWeightsInfo,
3326  descriptorName, "inputToInputWeights", "inputToCellWeights");
3327  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToOutputWeightsInfo,
3328  descriptorName, "inputToInputWeights", "inputToOutputWeights");
3329 
3330  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToInputWeightsInfo,
3331  descriptorName, "inputToInputWeights", "recurrentToInputWeights");
3332  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToForgetWeightsInfo,
3333  descriptorName, "inputToInputWeights", "recurrentToForgetWeights");
3334  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToCellWeightsInfo,
3335  descriptorName, "inputToInputWeights", "recurrentToCellWeights");
3336  ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToOutputWeightsInfo,
3337  descriptorName, "inputToInputWeights", "recurrentToOutputWeights");
3338 
3339  // Validate number of dimensions and number of elements in bias tensors
3340  ValidatePointer(m_InputGateBias, descriptorName, "InputGateBias");
3341  auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3342  ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, outputSize, " InputGateBias");
3343 
3344  ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3345  auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3346  ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, outputSize, " ForgetGateBias");
3347 
3348  ValidatePointer(m_CellBias, descriptorName, "CellBias");
3349  auto cellBiasInfo = m_CellBias->GetTensorInfo();
3350  ValidateTensorNumDimNumElem(cellBiasInfo, 1, outputSize, " CellBias");
3351 
3352  ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3353  auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3354  ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, outputSize, " OutputGateBias");
3355 
3356  // Validate data types for bias tensors (all should match each other)
3357  ValidateDataTypes(inputGateBiasInfo, biasSupportedTypes, descriptorName);
3358 
3359  ValidateTensorDataTypesMatch(inputGateBiasInfo, forgetGateBiasInfo, descriptorName,
3360  "inputGateBias", "forgetGateBias");
3361  ValidateTensorDataTypesMatch(inputGateBiasInfo, cellBiasInfo, descriptorName,
3362  "inputGateBias", "cellBias");
3363  ValidateTensorDataTypesMatch(inputGateBiasInfo, outputGateBiasInfo, descriptorName,
3364  "inputGateBias", "outputGateBias");
3365 
3366  // Validate bias tensor quantization info
3367  ValidateBiasTensorQuantization(inputGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3368  ValidateBiasTensorQuantization(forgetGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3369  ValidateBiasTensorQuantization(cellBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3370  ValidateBiasTensorQuantization(outputGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName);
3371 }
3372 
3373 void AbsQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3374 {
3375  const std::string descriptorName{"AbsQueueDescriptor"};
3376 
3377  ValidateNumInputs(workloadInfo, descriptorName, 1);
3378  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3379 
3380  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3381  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3382 
3383  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3384 
3385  std::vector<DataType> supportedTypes =
3386  {
3394  };
3395 
3396  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3397  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3398 }
3399 
3400 void SliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3401 {
3402  const std::string descriptorName{"SliceQueueDescriptor"};
3403 
3404  ValidateNumInputs(workloadInfo, descriptorName, 1);
3405  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3406 
3407  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3408  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3409 
3410  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3411 
3412  const unsigned int rank = inputTensorInfo.GetNumDimensions();
3413  if (rank > 4)
3414  {
3415  throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
3416  }
3417 
3418  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, rank, "output");
3419 
3420  // Check if m_Begin and m_Size have the expected length
3421  if (m_Parameters.m_Begin.size() != rank)
3422  {
3423  throw InvalidArgumentException(descriptorName +
3424  ": Length of begin offset descriptor must equal rank " + std::to_string(rank));
3425  }
3426  if (m_Parameters.m_Size.size() != rank)
3427  {
3428  throw InvalidArgumentException(descriptorName +
3429  ": Length of size descriptor must equal rank " + std::to_string(rank));
3430  }
3431 
3432  // Check if the shape of the output tensor matches m_Size
3433  const TensorShape& outputShape = outputTensorInfo.GetShape();
3434  for (unsigned int i = 0u; i < rank; ++i)
3435  {
3436  if (m_Parameters.m_Size[i] != outputShape[i])
3437  {
3438  throw InvalidArgumentException(descriptorName + ": Size descriptor does not match output tensor.");
3439  }
3440  }
3441 
3442  // Check if the sum of begin offset and size in a given dimension
3443  // does not exceed the size of corresponding input
3444  const TensorShape& inputShape = inputTensorInfo.GetShape();
3445  for(unsigned int i = 0u; i < rank; ++i)
3446  {
3447  if (m_Parameters.m_Begin[i] + m_Parameters.m_Size[i] > inputShape[i])
3448  {
3449  throw InvalidArgumentException(descriptorName + ": Sum of begin offset and size for dimension " +
3450  std::to_string(i) + " exceeds input size.");
3451  }
3452  }
3453 }
3454 
3456 {
3457  const std::string descriptorName{"DepthToSpaceQueueDescriptor"};
3458 
3459  ValidateNumInputs(workloadInfo, descriptorName, 1);
3460  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3461 
3462  const TensorInfo& inputInfo = workloadInfo.m_InputTensorInfos[0];
3463  const TensorInfo& outputInfo = workloadInfo.m_OutputTensorInfos[0];
3464 
3465  ValidateTensorNumDimensions(inputInfo, descriptorName, 4, "input");
3466  ValidateTensorNumDimensions(outputInfo, descriptorName, 4, "output");
3467 
3468  std::vector<DataType> supportedTypes =
3469  {
3476  };
3477 
3478  ValidateDataTypes(inputInfo, supportedTypes, descriptorName);
3479  ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
3480 
3481  ValidateTensorNumElementsMatch(inputInfo, outputInfo, descriptorName, "input", "output");
3482 
3483  if (m_Parameters.m_BlockSize == 0)
3484  {
3485  throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
3486  }
3487 
3488  DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
3489  const unsigned int wIndex = dimensionIndices.GetWidthIndex();
3490  const unsigned int hIndex = dimensionIndices.GetHeightIndex();
3491  const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
3492 
3493  const TensorShape& outputShape = outputInfo.GetShape();
3494  if (outputShape[hIndex] % m_Parameters.m_BlockSize != 0 || outputShape[wIndex] % m_Parameters.m_BlockSize != 0)
3495  {
3496  throw InvalidArgumentException(descriptorName + ": Output width and height shape"
3497  "must be divisible by block size.");
3498  }
3499 
3500  const TensorShape& inputShape = inputInfo.GetShape();
3501  if (inputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
3502  {
3503  throw InvalidArgumentException(descriptorName + ": The depth of the input tensor"
3504  "must be divisible by the square of block size." );
3505  }
3506 }
3507 
3508 void ComparisonQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3509 {
3510  const std::string descriptorName{"ComparisonQueueDescriptor"};
3511 
3512  ValidateNumInputs(workloadInfo, descriptorName, 2);
3513  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3514 
3515  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3516  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3517  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3518 
3519  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3520  inputTensorInfo1,
3521  outputTensorInfo,
3522  descriptorName,
3523  "input_0",
3524  "input_1");
3525 
3526  if (outputTensorInfo.GetDataType() != DataType::Boolean)
3527  {
3528  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3529  }
3530 }
3531 
3533 {
3534  const std::string descriptorName{"ElementwiseUnaryQueueDescriptor"};
3535 
3536  ValidateNumInputs(workloadInfo, descriptorName, 1);
3537  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3538 
3539  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3540  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3541 
3542  ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3543 
3544  std::vector<DataType> supportedTypes =
3545  {
3553  };
3554 
3555  std::vector<DataType> logicalSupportedTypes =
3556  {
3558  };
3559 
3560  if (m_Parameters.m_Operation == UnaryOperation::LogicalNot)
3561  {
3562  ValidateDataTypes(inputTensorInfo, logicalSupportedTypes, descriptorName);
3563  }
3564  else
3565  {
3566  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3567  }
3568 
3569 
3570  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3571 }
3572 
3573 void RankQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3574 {
3575  const std::string descriptorName{"RankQueueDescriptor"};
3576 
3577  ValidateNumInputs(workloadInfo, descriptorName, 1);
3578  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3579 
3580  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3581  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3582 
3583  ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
3584  ValidateTensorNumElements(outputTensorInfo, descriptorName, 1, "output");
3585 
3586  std::vector<DataType> supportedTypes =
3587  {
3596  };
3597 
3598  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3599  ValidateDataTypes(outputTensorInfo, { DataType::Signed32 }, descriptorName);
3600 }
3601 
3603 {
3604  const std::string descriptorName{"LogicalBinaryQueueDescriptor"};
3605 
3606  ValidateNumInputs(workloadInfo, descriptorName, 2);
3607  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3608 
3609  const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3610  const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3611  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3612 
3613  ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3614  inputTensorInfo1,
3615  outputTensorInfo,
3616  descriptorName,
3617  "input_0",
3618  "input_1");
3619 
3620  if (inputTensorInfo0.GetDataType() != DataType::Boolean)
3621  {
3622  throw InvalidArgumentException(descriptorName + ": Input tensor 0 type must be Boolean.");
3623  }
3624 
3625  if (inputTensorInfo1.GetDataType() != DataType::Boolean)
3626  {
3627  throw InvalidArgumentException(descriptorName + ": Input tensor 1 type must be Boolean.");
3628  }
3629 
3630  if (outputTensorInfo.GetDataType() != DataType::Boolean)
3631  {
3632  throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3633  }
3634 }
3635 
3636 void ReduceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3637 {
3638  const std::string descriptorName{"ReduceQueueDescriptor"};
3639 
3640  ValidateNumInputs(workloadInfo, descriptorName, 1);
3641  ValidateNumOutputs(workloadInfo, descriptorName, 1);
3642 
3643  const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3644  const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3645 
3646  std::vector<DataType> supportedTypes =
3647  {
3655  };
3656 
3657  ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3658  ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3659 }
3660 
3661 } // 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
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:423
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:187
constexpr bool IsQuantizedType()
Definition: TypesUtils.hpp:249
#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:437
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:485
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
armnn::TensorInfo anchorsInfo({ 6, 4 }, armnn::DataType::Float32)
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:241
std::vector< float > GetQuantizationScales() const
Definition: Tensor.cpp:442
bool HasMultipleQuantizationScales() const
Definition: Tensor.hpp:197
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:180
constexpr bool IsQuantized8BitType(DataType dataType)
Definition: TypesUtils.hpp:254
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< TensorInfo > m_InputTensorInfos
void Validate(const WorkloadInfo &workloadInfo) const
DataType
Definition: Types.hpp:32
#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:469
float GetQuantizationScale() const
Definition: Tensor.cpp:452
Provides access to the appropriate indexes for Channels, Height and Width based on DataLayout...
DataType GetDataType() const
Definition: Tensor.hpp:194
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
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
armnn::TensorInfo scoresInfo({ 1, 6, 3 }, armnn::DataType::Float32)
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 inputs and outputs to 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:191
unsigned int GetChannelsIndex() const
bool IsQuantized() const
Definition: Tensor.cpp:495
void Validate(const WorkloadInfo &workloadInfo) const
unsigned int GetNumElements() const
Definition: Tensor.hpp:192
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< unsigned int > m_Origin