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