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