ArmNN
 25.11
Loading...
Searching...
No Matches
WorkloadData.cpp
Go to the documentation of this file.
1//
2// Copyright © 2017-2024 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
13#include <armnn/Logging.hpp>
14
15#include <algorithm>
16#include <iomanip>
17#include <string>
18#include <sstream>
19
20#include <fmt/format.h>
21
22using namespace armnnUtils;
23
24namespace armnn
25{
26
27//---------------------------------------------------------------
29{
30 switch (inputDataType)
31 {
33 return DataType::Float16;
36 return DataType::Float32;
41 return DataType::Signed32;
42 default:
43 throw InvalidArgumentException("GetBiasDataType(): Unsupported data type.");
44 }
45}
46
47namespace
48{
49
50//---------------------------------------------------------------
51//android ndk does not support std::to_string function.
52template <typename T>
53std::string to_string(T value)
54{
55 std::ostringstream os;
56 os << value;
57 return os.str();
58}
59
60//---------------------------------------------------------------
61void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName)
62{
63 if (!ptr)
64 {
65 throw InvalidArgumentException(descName + ": Invalid null pointer. The " +
66 paramName + " parameter must be set.");
67 }
68}
69
70//---------------------------------------------------------------
71void ValidateTensorShapesMatch(const TensorInfo& first,
72 const TensorInfo& second,
73 std::string const& descName,
74 std::string const& firstName,
75 std::string const& secondName)
76{
77 if (first.GetShape() != second.GetShape())
78 {
79 throw InvalidArgumentException(descName + ": "
80 + firstName + " & " + secondName + " must have identical shapes");
81 }
82}
83
84//---------------------------------------------------------------
85void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
86{
87 if (workloadInfo.m_InputTensorInfos.size() != expectedSize)
88 {
89 throw InvalidArgumentException(descName +
90 ": Requires exactly " + to_string(expectedSize) + "input(s). " +
91 to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided.");
92 }
93}
94
95//---------------------------------------------------------------
96void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
97{
98 if (workloadInfo.m_OutputTensorInfos.size() != expectedSize)
99 {
100 throw InvalidArgumentException(descName +
101 ": Requires exactly " + to_string(expectedSize) + " output(s). " +
102 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
103 }
104}
105
106//---------------------------------------------------------------
107
108//---------------------------------------------------------------
109void ValidateTensorNumElements(const TensorInfo& tensor,
110 std::string const& descName,
111 unsigned int numElements,
112 std::string const& tensorName)
113{
114 if (tensor.GetNumElements() != numElements)
115 {
116 throw InvalidArgumentException(descName + ": Expected " + to_string(numElements) + " but got " +
117 to_string(tensor.GetNumElements()) + " elements for " +
118 tensorName + " tensor.");
119 }
120}
121
122//---------------------------------------------------------------
123void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
124 const std::string& descName, std::string const& tensorName)
125{
126 if (tensor.GetDataType() != dataType)
127 {
128 throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
129 GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
130 }
131}
132
133void ValidPerAxisQuantizedDataType(const TensorInfo& tensor, const std::string& descName, const std::string& tensorName)
134{
135 if (tensor.GetDataType() != DataType::QSymmS8)
136 {
137 throw InvalidArgumentException(descName +
138 ": Expected data type which supports per-axis quantization scheme but got " +
139 GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
140 }
141}
142
143//---------------------------------------------------------------
144void ValidateTensorQuantizationSpace(const TensorInfo& first,
145 const TensorInfo& second,
146 const std::string& descName,
147 std::string const& firstName,
148 std::string const& secondName)
149{
150 if (!first.IsQuantized() ||
151 !second.IsQuantized())
152 {
153 // Not a quantized type, ignore the validation
154 return;
155 }
156
157 DataType firstDataType = first.GetDataType();
158 DataType secondDataType = second.GetDataType();
159
160 if (firstDataType != secondDataType)
161 {
162 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
163 " must be of the same quantized type, " +
164 firstName + " is " + GetDataTypeName(firstDataType) + ", " +
165 secondName + " is " + GetDataTypeName(secondDataType));
166 }
167
168 if (!first.IsTypeSpaceMatch(second))
169 {
170 throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName +
171 " must have the same quantization space, " +
172 firstName + " has offset " + to_string(first.GetQuantizationOffset()) +
173 " and scale " + to_string(first.GetQuantizationScale()) + ", " +
174 secondName + " has offset " + to_string(second.GetQuantizationOffset()) +
175 " and scale " + to_string(second.GetQuantizationScale()));
176 }
177}
178
179//---------------------------------------------------------------
180void ValidateBiasTensorQuantization(const TensorInfo& biasTensor,
181 const TensorInfo& weightsTensorInfo,
182 const std::string& descName)
183{
184 if (biasTensor.GetQuantizationOffset() != 0)
185 {
186 throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
187 to_string(biasTensor.GetQuantizationOffset()));
188 }
189
190 if (biasTensor.HasMultipleQuantizationScales() || weightsTensorInfo.HasMultipleQuantizationScales())
191 {
192 // Validate per-axis quantization scales
193 const std::vector<float>& weightScales = weightsTensorInfo.GetQuantizationScales();
194 const std::vector<float>& biasScales = biasTensor.GetQuantizationScales();
195
196 if (weightScales.size() != biasScales.size())
197 {
198 std::stringstream msg;
199 msg << descName << ": Expected matching number of per-axis quantization scales for weights and bias, "
200 << "but got different values. This is currently unsupported: weights=" << weightScales.size()
201 << ", biases=" << biasScales.size();
202 throw InvalidArgumentException(msg.str(), CHECK_LOCATION());
203 }
204 }
205}
206
207//---------------------------------------------------------------
208void ValidateTensors(const std::vector<ITensorHandle*>& vec,
209 unsigned int numExpected,
210 const std::string& descName,
211 const std::string& varName)
212{
213 if (vec.empty() && numExpected > 0)
214 {
215 throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
216 }
217
218 for (unsigned int i = 0; i < numExpected; ++i)
219 {
220 if (!vec[i])
221 {
222 throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
223 }
224 }
225}
226
227//---------------------------------------------------------------
228void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
229 const TensorInfo& second,
230 const TensorInfo& output,
231 std::string const& descName,
232 std::string const& firstName,
233 std::string const& secondName)
234{
235 // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
236 // broadcasted.
237 // NOTE: This check is dependent on the AddBroadcastReshapeLayerImpl optimization having been applied to the layer.
238 if (first.GetNumDimensions() != second.GetNumDimensions())
239 {
240 throw InvalidArgumentException(descName + ": Tensors "
241 + firstName + " & " + secondName
242 + " must have the same number of dimensions in order to be broadcasted");
243 }
244 uint32_t numDims = first.GetNumDimensions();
245 std::vector<uint32_t> outputDims(numDims, 0u);
246 for (uint32_t i = 0; i < numDims; i++)
247 {
248 const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i];
249 const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1);
250 if (dimsNotEqual && dimsNotOne)
251 {
252 throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes");
253 }
254 outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]);
255 }
256 TensorShape broadcastShape = TensorShape(armnn::numeric_cast<unsigned int>(outputDims.size()), outputDims.data());
257 if (broadcastShape != output.GetShape())
258 {
259 throw InvalidArgumentException(descName + ": The tensor shape resulting from adding "
260 + firstName + " & " + secondName
261 + " does not match the output shape");
262 }
263}
264
265//---------------------------------------------------------------
266void ValidateDataTypes(const TensorInfo& info,
267 const std::vector<armnn::DataType>& supportedTypes,
268 std::string const& descName)
269{
270 auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
271 if (iterator == supportedTypes.end())
272 {
273 throw InvalidArgumentException(descName + ": " + " Tensor type " + GetDataTypeName(info.GetDataType()) +
274 " is not supported.");
275 }
276}
277
278//---------------------------------------------------------------
279void ValidateTensorDataTypesMatch(const TensorInfo& first,
280 const TensorInfo& second,
281 std::string const& descName,
282 std::string const& firstName,
283 std::string const& secondName)
284{
285 if (first.GetDataType() != second.GetDataType())
286 {
287 throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
288 " must have identical data types.");
289 }
290}
291
292//---------------------------------------------------------------
293void ValidateTensorNumElementsMatch(const TensorInfo& first,
294 const TensorInfo& second,
295 std::string const& descName,
296 std::string const& firstName,
297 std::string const& secondName)
298{
299 if (first.GetNumElements() != second.GetNumElements())
300 {
301 throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName +
302 " must have the same number of elements.");
303 }
304}
305
306void ValidateWeightDataType(const TensorInfo& inputInfo,
307 const TensorInfo& weightInfo,
308 const std::string& descName)
309{
310 const DataType inputType = inputInfo.GetDataType();
311 if (IsQuantized8BitType(inputType))
312 {
313 const std::vector<DataType> validTypes =
314 {
318 };
319
320 ValidateDataTypes(weightInfo, validTypes, descName);
321 }
322 else
323 {
324 ValidateTensorDataTypesMatch(inputInfo, weightInfo, descName, "input", "weight");
325 }
326}
327
328void ValidatePerAxisQuantizationDimension(const TensorInfo& tensorInfo,
329 const std::string& descName,
330 const std::string& tensorName)
331{
332 const Optional<unsigned int>& quantizationDim = tensorInfo.GetQuantizationDim();
333 if (!quantizationDim.has_value())
334 {
335 throw InvalidArgumentException(fmt::format("{0}: Quantization dimension for per-axis quantization "
336 "not set on tensor {1}.", descName, tensorName));
337 }
338}
339
340void ValidatePerAxisQuantizationOffset(const TensorInfo& tensorInfo,
341 const std::string& descName,
342 const std::string& tensorName)
343{
344 int32_t quantizationOffset = tensorInfo.GetQuantizationOffset();
345 if (quantizationOffset != 0)
346 {
347 throw InvalidArgumentException(fmt::format(
348 "{0}: Quantization offset for per-axis quantization expected to be 0 on tensor {1}, but got: {2}",
349 descName, tensorName, quantizationOffset));
350 }
351}
352
353void ValidatePerAxisQuantization(const TensorInfo& inputInfo,
354 const TensorInfo& outputInfo,
355 const TensorInfo& weightInfo,
356 const Optional<TensorInfo>& optionalBiasInfo,
357 const std::string& descName)
358{
359 if (weightInfo.HasPerAxisQuantization())
360 {
361 const DataType inputDataType = inputInfo.GetDataType();
362 const DataType outputDataType = outputInfo.GetDataType();
363
364 const bool canHavePerAxisQuantization = (IsQuantized8BitType(inputDataType)) && inputDataType == outputDataType;
365
366 if (!canHavePerAxisQuantization)
367 {
368 throw InvalidArgumentException(fmt::format(
369 "{0}: Per-axis quantization parameters set on tensor {1}, but data type does not support "
370 "per-axis quantization.", descName, "weight"));
371 }
372
373
374 ValidPerAxisQuantizedDataType(weightInfo, descName, "weight");
375 ValidatePerAxisQuantizationDimension(weightInfo, descName, "weight");
376 ValidatePerAxisQuantizationOffset(weightInfo, descName, "weight");
377
378 if (optionalBiasInfo.has_value())
379 {
380 const TensorInfo& biasInfo = optionalBiasInfo.value();
381 if (!biasInfo.HasPerAxisQuantization())
382 {
383 throw InvalidArgumentException(fmt::format(
384 "{}: Per-axis quantization parameters not set on bias tensor, "
385 "despite being set on weight tensor.", descName));
386 }
387
388 ValidateTensorDataType(biasInfo, DataType::Signed32, descName, "bias");
389 ValidatePerAxisQuantizationDimension(biasInfo, descName, "bias");
390 ValidatePerAxisQuantizationOffset(biasInfo, descName, "bias");
391 }
392 }
393}
394
395} // anonymous namespace
396
397//---------------------------------------------------------------
399 std::string const& descName,
400 unsigned int numDimensions,
401 std::string const& tensorName) const
402{
403 // If we're allowing expanded dimensions then numDimensions becomes the minimum number of Dimensions we can allow.
404 // Throw an Exception if the tensors has fewer than numDimensions or if the squeezed dimensions are greater than
405 // numDimensions.
407 {
408 unsigned int squeezedDims = 0;
409
410 for (unsigned int i = 0; i < tensor.GetNumDimensions(); ++i)
411 {
412 if (tensor.GetShape()[i] != 1)
413 {
414 ++squeezedDims;
415 }
416 }
417 if (tensor.GetNumDimensions() < numDimensions || squeezedDims > numDimensions)
418 {
419 throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " or less but got " +
420 to_string(tensor.GetNumDimensions()) + " dimensions for " +
421 tensorName + " tensor.");
422 }
423 }
424 else
425 {
426 if (tensor.GetNumDimensions() != numDimensions)
427 {
428 throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " +
429 to_string(tensor.GetNumDimensions()) + " dimensions for " +
430 tensorName + " tensor.");
431 }
432 }
433}
434
435//---------------------------------------------------------------
437 unsigned int numDimension,
438 unsigned int numElements,
439 std::string const& tensorName) const
440{
441 const std::string functionName{"ValidateTensorNumDimNumElem"};
442 ValidateTensorNumDimensions(tensorInfo, functionName, numDimension, tensorName);
443 ValidateTensorNumElements(tensorInfo, functionName, numElements, tensorName);
444}
445
446//---------------------------------------------------------------
447void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
448 unsigned int numExpectedIn, unsigned int numExpectedOut) const
449{
450 ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
451 ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
452}
453
454//---------------------------------------------------------------
455void MapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
456{
457 const std::string descriptorName{"MapQueueDescriptor"};
458
459 ValidateNumInputs(workloadInfo, descriptorName, 1);
460 ValidateNumOutputs(workloadInfo, descriptorName, 0);
461
462 for (unsigned int i = 0; i < m_Inputs.size(); ++i)
463 {
464 if (!m_Inputs[i])
465 {
467 fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
468 }
469 }
470}
471
472//---------------------------------------------------------------
473void UnmapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
474{
475 const std::string descriptorName{"UnmapQueueDescriptor"};
476
477 ValidateNumInputs(workloadInfo, descriptorName, 1);
478 ValidateNumOutputs(workloadInfo, descriptorName, 0);
479
480 for (unsigned int i = 0; i < m_Inputs.size(); ++i)
481 {
482 if (!m_Inputs[i])
483 {
485 fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i)));
486 }
487 }
488}
489
490//---------------------------------------------------------------
491void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
492{
493 const std::string descriptorName{"MemCopyQueueDescriptor"};
494
495 ValidateNumInputs(workloadInfo, descriptorName, 1);
496 ValidateNumOutputs(workloadInfo, descriptorName , 1);
497
498 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
499 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
500
501 ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
502 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
503
504 if (m_Inputs.size() != m_Outputs.size())
505 {
506 throw InvalidArgumentException(fmt::format(
507 "{0}: Number of inputs ({1}) does not match the number of outputs ({2}).",
508 descriptorName, m_Inputs.size(), m_Outputs.size()));
509 }
510
511 for (unsigned int i = 0; i < m_Inputs.size(); ++i)
512 {
513 if (!m_Inputs[i])
514 {
515 throw InvalidArgumentException(fmt::format(
516 "{0}: Invalid NULL input {1}.", descriptorName, i));
517 }
518
519 if (!m_Outputs[i])
520 {
521 throw InvalidArgumentException(fmt::format("{0}: Invalid NULL output {1}", descriptorName, i));
522 }
523 }
524}
525
526//---------------------------------------------------------------
528{
529 ValidateNumInputs(workloadInfo, "MemImportQueueDescriptor", 1);
530 ValidateNumOutputs(workloadInfo, "MemImportQueueDescriptor" , 1);
531
532 if (workloadInfo.m_InputTensorInfos.size() != 1)
533 {
534 throw InvalidArgumentException(fmt::format("Number of input infos ({}) is not 1.",
535 workloadInfo.m_InputTensorInfos.size()));
536
537 }
538
539 if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
540 {
541 throw InvalidArgumentException(fmt::format(
542 "Number of input infos ({0}) does not match the number of output infos ({1})",
543 workloadInfo.m_InputTensorInfos.size(), workloadInfo.m_OutputTensorInfos.size()));
544 }
545
546 for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
547 {
548 if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
549 workloadInfo.m_OutputTensorInfos[i].GetNumElements())
550 {
551 throw InvalidArgumentException(fmt::format(
552 "Number of elements for tensor input and output {} does not match", i ));
553 }
554 }
555
556 if (m_Inputs.size() != 1)
557 {
558 throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
559 }
560
561 if (m_Inputs.size() != m_Outputs.size())
562 {
563 throw InvalidArgumentException(fmt::format(
564 "Number of inputs ({0}) does not match the number of outputs ({1})",
565 m_Inputs.size(), m_Outputs.size()));
566 }
567
568 for (unsigned int i = 0; i < m_Inputs.size(); ++i)
569 {
570 if (!m_Inputs[i])
571 {
572 throw InvalidArgumentException(fmt::format("Invalid null input {}", i));
573 }
574
575 if (!m_Outputs[i])
576 {
577 throw InvalidArgumentException(fmt::format("Invalid null output {}", i));
578 }
579 }
580}
581
582//---------------------------------------------------------------
583void MemSyncQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
584{
585 ValidateNumInputs(workloadInfo, "MemSyncQueueDescriptor", 1);
586
587 if (m_Inputs.size() != 1)
588 {
589 throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size()));
590 }
591
592 if (m_Outputs.size() != 0)
593 {
594 throw InvalidArgumentException(fmt::format("Number of outputs ({}) is not 0.", m_Outputs.size()));
595 }
596
597 if (!m_Inputs[0])
598 {
599 throw InvalidArgumentException(fmt::format("Invalid null input 0"));
600 }
601}
602
603//---------------------------------------------------------------
605{
606 const std::string descriptorName{"ActivationQueueDescriptor"};
607
608 ValidateNumInputs(workloadInfo, descriptorName, 1);
609 ValidateNumOutputs(workloadInfo, descriptorName, 1);
610
611 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
612 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
613
614 std::vector<DataType> supportedTypes =
615 {
622 };
623
624 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
625 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
626 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
627}
628
630{
631 const std::string descriptorName{"ArgMinMaxQueueDescriptor"};
632
633 ValidateNumInputs(workloadInfo, descriptorName, 1);
634 ValidateNumOutputs(workloadInfo, descriptorName, 1);
635
636 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
637 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
638
639 if (outputTensorInfo.GetDataType() != DataType::Signed32 &&
640 outputTensorInfo.GetDataType() != DataType::Signed64)
641 {
642 throw InvalidArgumentException(descriptorName + ": Output of ArgMinMax layer must be Int32 or Int64.");
643 }
644
645 std::vector<DataType> supportedInputTypes =
646 {
655 };
656
657 ValidateDataTypes(inputTensorInfo, supportedInputTypes, descriptorName);
658
659 auto inputShape = inputTensorInfo.GetShape();
660 auto outputShape = outputTensorInfo.GetShape();
661
662 auto inputNumDimensions = inputShape.GetNumDimensions();
663 auto unsignedAxis = armnnUtils::GetUnsignedAxis(inputNumDimensions, m_Parameters.m_Axis);
664
665 const std::string outputShapeError{": Output tensor shape does not match shape inferred from input tensor."};
666
667 // 1D input shape results in scalar output shape
668 if (inputShape.GetNumDimensions() == 1)
669 {
670 if (outputShape.GetNumDimensions() != 1 && outputShape[0] != 1)
671 {
672 throw InvalidArgumentException(descriptorName + outputShapeError);
673 }
674 }
675 else
676 {
677 for (unsigned int i = 0; i < unsignedAxis; ++i)
678 {
679 if (outputShape[i] != inputShape[i])
680 {
681 throw InvalidArgumentException(descriptorName + outputShapeError);
682 }
683 }
684
685 for (auto i = unsignedAxis + 1; i < inputNumDimensions; ++i)
686 {
687 if (outputShape[i - 1] != inputShape[i])
688 {
689 throw InvalidArgumentException(descriptorName + outputShapeError);
690 }
691 }
692 }
693}
694
695void CastQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
696{
697 const std::string descriptorName{"CastQueueDescriptor"};
698
699 ValidateNumInputs(workloadInfo, descriptorName, 1);
700 ValidateNumOutputs(workloadInfo, descriptorName, 1);
701
702 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
703 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
704
705 std::vector<DataType> supportedTypes =
706 {
717 };
718
719 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
720 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
721}
722
723void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
724{
725 const std::string descriptorName{"SoftmaxQueueDescriptor"};
726
727 ValidateNumInputs(workloadInfo, descriptorName, 1);
728 ValidateNumOutputs(workloadInfo, descriptorName, 1);
729
730 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
731 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
732
733 std::vector<DataType> supportedTypes =
734 {
741 };
742
743 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
744 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
745 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
746}
747
748void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
749{
750 const std::string descriptorName{"SplitterQueueDescriptor"};
751
752 ValidateNumInputs(workloadInfo, descriptorName, 1);
753
754 // Check the supported data types
755 std::vector<DataType> supportedTypes =
756 {
765 };
766
767 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
768 for (unsigned long i = 0ul; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
769 {
770 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[i];
771 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
772
773 const std::string outputName = "output_" + std::to_string(i);
774 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", outputName);
775 }
776
777 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
778 {
779 throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
780 }
781
782 if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
783 {
785 descriptorName + ": Number of split windows "
786 "has to match number of workloadInfo.m_OutputTensorInfos. "
787 "Number of windows: " +
788 to_string(m_ViewOrigins.size()) +
789 ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
790 }
791
792 //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
793 std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
794 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
795 {
796 //Checks that the dimensionality of input is same as the split windows.
797 ViewOrigin const& e = m_ViewOrigins[w];
798 if (e.m_Origin.size() != inputDims)
799 {
800 throw InvalidArgumentException(descriptorName + ": Window origin have to "
801 "have the same dimensionality as the input tensor. "
802 "Window origin (index: " +
803 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
804 " dimensions, the input "
805 "tensor has " +
806 to_string(inputDims) + " dimensions.");
807 }
808 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
809 {
810 if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
811 workloadInfo.m_InputTensorInfos[0].GetShape()[i])
812 {
813 throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
814 "be smaller or equal than the size of the input in that coord.");
815 }
816 }
817 }
818}
819
820void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
821{
822 const std::string descriptorName{"ConcatQueueDescriptor"};
823
824 ValidateNumOutputs(workloadInfo, descriptorName, 1);
825
826 if (m_Inputs.size() <= 0)
827 {
828 throw InvalidArgumentException(descriptorName + ": At least one input needs to be provided.");
829 }
830 if (m_Outputs.size() <= 0)
831 {
832 throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided.");
833 }
834
835 if (workloadInfo.m_InputTensorInfos.size() <= 0)
836 {
837 throw InvalidArgumentException(descriptorName + ": At least one TensorInfo input needs to be provided.");
838 }
839 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
840 {
841 throw InvalidArgumentException(descriptorName + ": At least one TensorInfo output needs to be provided.");
842 }
843
844 if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
845 {
846 throw InvalidArgumentException(descriptorName + ": Invalid concatenation axis provided.");
847 }
848
849 if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
850 {
851 return;
852 }
853
854 if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
855 {
857 descriptorName + ": Number of split windows "
858 "has to match number of workloadInfo.m_InputTensorInfos. "
859 "Number of windows: " +
860 to_string(m_ViewOrigins.size()) +
861 ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
862 }
863
864 //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
865 std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
866 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
867 {
868 //Checks that the dimensionality of output is same as the split windows.
869 ViewOrigin const& e = m_ViewOrigins[w];
870 if (e.m_Origin.size() != outputDims)
871 {
872 throw InvalidArgumentException(descriptorName + ": Window origin have to "
873 "have the same dimensionality as the output tensor. "
874 "Window origin (index: " +
875 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
876 " dimensions, the output "
877 "tensor has " +
878 to_string(outputDims) + " dimensions.");
879 }
880 //Checks that the merge windows are within the output tensor.
881 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
882 {
883 if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
884 > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
885 {
886 throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to "
887 "be smaller or equal than the size of the output in that coord.");
888 }
889 }
890 }
891
892 // Check the supported data types
893 std::vector<DataType> supportedTypes =
894 {
903 };
904
905 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
906 for (unsigned long i = 0ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
907 {
908 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[i];
909 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
910
911 const std::string inputName = "input_" + std::to_string(i);
912 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, inputName, "output");
913 }
914}
915
916void StackQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
917{
918 const std::string descriptorName{"StackQueueDescriptor"};
919
920 ValidateNumOutputs(workloadInfo, descriptorName, 1);
921
922 if (m_Parameters.m_NumInputs != workloadInfo.m_InputTensorInfos.size())
923 {
924 throw InvalidArgumentException(descriptorName + ": Must have the defined number of input tensors.");
925 }
926
927 // All inputs must have the same shape, which is defined in parameters
928 const TensorShape& inputShape = m_Parameters.m_InputShape;
929 for (unsigned int i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
930 {
931 if (workloadInfo.m_InputTensorInfos[i].GetShape() != inputShape)
932 {
933 throw InvalidArgumentException(descriptorName + ": All input tensor shapes must match the defined shape.");
934 }
935 }
936
937 if (inputShape.GetNumDimensions() > 4)
938 {
939 throw InvalidArgumentException(descriptorName + ": Input tensor may have up to 4 dimensions.");
940 }
941
942 // m_Axis is 0-based and may take values from 0 to the number of input dimensions (inclusive),
943 // since the output tensor has an additional dimension.
944 if (m_Parameters.m_Axis > inputShape.GetNumDimensions())
945 {
946 throw InvalidArgumentException(descriptorName + ": Axis may not be greater "
947 "than the number of input dimensions.");
948 }
949
950 // Output shape must be as inferred from the input shape
951 const TensorShape& outputShape = workloadInfo.m_OutputTensorInfos[0].GetShape();
952 for (unsigned int i = 0; i < m_Parameters.m_Axis; ++i)
953 {
954 if (outputShape[i] != inputShape[i])
955 {
956 throw InvalidArgumentException(descriptorName + ": Output tensor must "
957 "match shape inferred from input tensor.");
958 }
959 }
960
961 if (outputShape[m_Parameters.m_Axis] != m_Parameters.m_NumInputs)
962 {
963 throw InvalidArgumentException(descriptorName + ": Output tensor must "
964 "match shape inferred from input tensor.");
965 }
966
967 for (unsigned int i = m_Parameters.m_Axis + 1; i < inputShape.GetNumDimensions() + 1; ++i)
968 {
969 if (outputShape[i] != inputShape[i-1])
970 {
971 throw InvalidArgumentException(descriptorName + ": Output tensor must "
972 "match shape inferred from input tensor.");
973 }
974 }
975
976 if (outputShape.GetNumDimensions() > 5)
977 {
978 throw InvalidArgumentException(descriptorName + ": Output tensor may have up to 5 dimensions.");
979 }
980
981 // Check the supported data types
982 std::vector<DataType> supportedTypes =
983 {
993 };
994
995 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
996
997 for (unsigned int i = 1ul; i < workloadInfo.m_InputTensorInfos.size(); ++i)
998 {
999 ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1000 workloadInfo.m_InputTensorInfos[i],
1001 descriptorName,
1002 "input_0",
1003 "input_" + std::to_string(i));
1004 }
1005
1006 ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
1007 workloadInfo.m_OutputTensorInfos[0],
1008 descriptorName,
1009 "input_0",
1010 "output");
1011}
1012
1013void FillQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1014{
1015 const std::string descriptorName{"FillQueueDescriptor"};
1016
1017 ValidateNumInputs(workloadInfo, descriptorName, 1);
1018 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1019
1020 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1021 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1022
1023 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 1, "input");
1024
1025 std::vector<DataType> supportedTypes =
1026 {
1031 };
1032
1033 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1034}
1035
1037{
1038 const std::string descriptorName{"FullyConnectedQueueDescriptor"};
1039
1040 uint32_t numInputs = 2;
1041 if (m_Parameters.m_BiasEnabled)
1042 {
1043 numInputs = 3;
1044 }
1045
1046 ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1047 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1048
1049 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1050 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1051
1052 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1053
1054 if (!(inputTensorInfo.GetNumDimensions() == 2 || inputTensorInfo.GetNumDimensions() == 4))
1055 {
1056 throw InvalidArgumentException(descriptorName + ": Input tensor must have 2 or 4 dimensions.");
1057 }
1058
1059 TensorInfo weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1060 ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 2, "weight");
1061
1062 if (m_Parameters.m_BiasEnabled)
1063 {
1064 TensorInfo biasTensorInfo = workloadInfo.m_InputTensorInfos[2];
1065 // Validates type and quantization values.
1066 ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
1067 ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1068 ValidateTensorNumDimensions(biasTensorInfo, descriptorName, 1, "bias");
1069 }
1070
1071 // Check the supported data types
1072 std::vector<DataType> supportedTypes =
1073 {
1081 };
1082
1083 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1084
1085 // For FullyConnected, we allow to have BFloat16 input with Float32 output for optimization.
1086 if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1087 {
1088 if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1089 {
1090 throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1091 "for BFloat16 input.");
1092 }
1093 }
1094 else
1095 {
1096 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1097 }
1098}
1099
1100void FusedQueueDescriptor::Validate(const WorkloadInfo& /*workloadInfo*/) const
1101{
1102 // This is internally generated, so it should not need validation.
1103}
1104
1106{
1107 const std::string descriptorName{"NormalizationQueueDescriptor"};
1108
1109 ValidateNumInputs(workloadInfo, descriptorName, 1);
1110 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1111
1112 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1113 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1114
1115 // Check the supported data types
1116 std::vector<DataType> supportedTypes =
1117 {
1124 };
1125
1126 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1127
1128 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1129
1130 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1131}
1132
1134{
1135 const std::string descriptorName{"AdditionQueueDescriptor"};
1136
1137 ValidateNumInputs(workloadInfo, descriptorName, 2);
1138 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1139
1140 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1141 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1142 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1143
1144 std::vector<DataType> supportedTypes =
1145 {
1153 };
1154
1155 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1156 ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1157 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1158
1159 ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1160 ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1161
1162 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1163 inputTensorInfo1,
1164 outputTensorInfo,
1165 descriptorName,
1166 "input_0",
1167 "input_1");
1168}
1169
1171{
1172 const std::string descriptorName{"MultiplicationQueueDescriptor"};
1173
1174 ValidateNumInputs(workloadInfo, descriptorName, 2);
1175 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1176
1177 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
1178 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
1179 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1180
1181 std::vector<DataType> supportedTypes =
1182 {
1190 };
1191
1192 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
1193 ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
1194 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1195
1196 ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
1197 ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output");
1198
1199 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
1200 inputTensorInfo1,
1201 outputTensorInfo,
1202 descriptorName,
1203 "input_0",
1204 "input_1");
1205}
1206
1208{
1209 const std::string descriptorName{"BatchNormalizationQueueDescriptor"};
1210
1211 ValidateNumInputs(workloadInfo, descriptorName, 1);
1212 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1213
1214 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1215 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1216
1217 std::vector<DataType> supportedTypes =
1218 {
1225 };
1226
1227 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1228 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1229
1230 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1231 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1232
1233 ValidatePointer(m_Mean, descriptorName, "mean");
1234 ValidatePointer(m_Variance, descriptorName, "variance");
1235 ValidatePointer(m_Beta, descriptorName, "beta");
1236 ValidatePointer(m_Gamma, descriptorName, "gamma");
1237
1238 const TensorInfo& mean = m_Mean->GetTensorInfo();
1239 const TensorInfo& variance = m_Variance->GetTensorInfo();
1240 const TensorInfo& beta = m_Beta->GetTensorInfo();
1241 const TensorInfo& gamma = m_Gamma->GetTensorInfo();
1242
1243 ValidateTensorNumDimensions(mean, descriptorName, 1, "mean");
1244 ValidateTensorNumDimensions(variance, descriptorName, 1, "variance");
1245 ValidateTensorNumDimensions(beta, descriptorName, 1, "beta");
1246 ValidateTensorNumDimensions(gamma, descriptorName, 1, "gamma");
1247
1248 ValidateTensorShapesMatch(mean, variance, descriptorName, "mean", "variance");
1249 ValidateTensorShapesMatch(mean, beta, descriptorName, "mean", "beta");
1250 ValidateTensorShapesMatch(mean, gamma, descriptorName, "mean", "gamma");
1251}
1252
1254{
1255 const std::string descriptorName{"Convolution2dQueueDescriptor"};
1256
1257 uint32_t numInputs = 2;
1258 if (m_Parameters.m_BiasEnabled)
1259 {
1260 numInputs = 3;
1261 }
1262
1263 ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1264 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1265
1266 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1267 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1268
1269 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1270 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1271
1272 const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1273
1274 ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1275
1276 ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1277
1278 Optional<TensorInfo> optionalBiasTensorInfo;
1279 if (m_Parameters.m_BiasEnabled)
1280 {
1281 optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1282 const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1283
1284 ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1285 ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
1286 }
1287
1288 if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1289 {
1291 fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1292 "cannot be either negative or 0.",
1293 descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1294 }
1295
1296 ValidatePerAxisQuantization(inputTensorInfo,
1297 outputTensorInfo,
1298 weightTensorInfo,
1299 optionalBiasTensorInfo,
1300 descriptorName);
1301
1302 std::vector<DataType> supportedTypes =
1303 {
1311 };
1312
1313 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1314
1315 // For Convolution2d, we allow to have BFloat16 input with Float32 output for optimization.
1316 if (inputTensorInfo.GetDataType() == DataType::BFloat16)
1317 {
1318 if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32)
1319 {
1320 throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 "
1321 "for BFloat16 input.");
1322 }
1323 }
1324 else
1325 {
1326 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1327 }
1328}
1329
1331{
1332 const std::string descriptorName{"Convolution3dQueueDescriptor"};
1333
1334 uint32_t numInputs = 2;
1335 if (m_Parameters.m_BiasEnabled)
1336 {
1337 numInputs = 3;
1338 }
1339 ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1340 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1341
1342 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1343 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1344
1345 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 5, "input");
1346 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 5, "output");
1347
1348 const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1349 ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 5, "weight");
1350
1351 ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1352
1353 Optional<TensorInfo> optionalBiasTensorInfo;
1354 if (m_Parameters.m_BiasEnabled)
1355 {
1356 optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1357 const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1358
1359 ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1360 ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
1361 }
1362
1363 if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 || m_Parameters.m_StrideZ <= 0 )
1364 {
1366 fmt::format("{}: strideX (provided {}), strideY (provided {}) or strideZ (provided {})"
1367 "cannot be either negative or 0.",
1368 descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY, m_Parameters.m_StrideZ));
1369 }
1370
1371 ValidatePerAxisQuantization(inputTensorInfo,
1372 outputTensorInfo,
1373 weightTensorInfo,
1374 optionalBiasTensorInfo,
1375 descriptorName);
1376
1377 std::vector<DataType> supportedTypes =
1378 {
1386 };
1387
1388 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1389 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1390}
1391
1393{
1394 const std::string descriptorName{"DepthwiseConvolution2dQueueDescriptor"};
1395
1396 uint32_t numInputs = 2;
1397 if (m_Parameters.m_BiasEnabled)
1398 {
1399 numInputs = 3;
1400 }
1401
1402 ValidateNumInputs(workloadInfo, descriptorName, numInputs);
1403 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1404
1405 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1406 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1407
1408 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1409 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1410
1411 const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
1412 ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
1413
1414 if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 )
1415 {
1417 fmt::format("{}: dilationX (provided {}) and dilationY (provided {}) "
1418 "cannot be smaller than 1.",
1419 descriptorName, m_Parameters.m_DilationX, m_Parameters.m_DilationX));
1420 }
1421
1422 if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 )
1423 {
1425 fmt::format("{}: strideX (provided {}) and strideY (provided {}) "
1426 "cannot be either negative or 0.",
1427 descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY));
1428 }
1429
1430 if (weightTensorInfo.GetShape()[0] != 1)
1431 {
1432 throw InvalidArgumentException(fmt::format(
1433 "{0}: The weight format in armnn is expected to be [1, H, W, Cout]."
1434 "But first dimension is not equal to 1. Provided weight shape: [{1}, {2}, {3}, {4}]",
1435 descriptorName,
1436 weightTensorInfo.GetShape()[0],
1437 weightTensorInfo.GetShape()[1],
1438 weightTensorInfo.GetShape()[2],
1439 weightTensorInfo.GetShape()[3]));
1440 }
1441
1442 const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
1443 const unsigned int numWeightOutputChannelsRefFormat = weightTensorInfo.GetShape()[3];
1444 const unsigned int numWeightOutputChannelsAclFormat = weightTensorInfo.GetShape()[1];
1445 const unsigned int numOutputChannels = outputTensorInfo.GetShape()[channelIndex];
1446
1447 // Weights format has two valid options: [1, H, W, Cout] (CpuRef) or [1, Cout, H, W] (CpuAcc/GpuAcc).
1448 bool validRefFormat = (numWeightOutputChannelsRefFormat == numOutputChannels);
1449 bool validAclFormat = (numWeightOutputChannelsAclFormat == numOutputChannels);
1450
1451 if (!(validRefFormat || validAclFormat))
1452 {
1453 throw InvalidArgumentException(fmt::format(
1454 "{0}: The weight format in armnn is expected to be [1, H, W, Cout] (CpuRef) or [1, Cout, H, W] "
1455 "(CpuAcc/GpuAcc). But neither the 4th (CpuRef) or 2nd (CpuAcc/GpuAcc) dimension is equal to Cout."
1456 "Cout = {1} Provided weight shape: [{2}, {3}, {4}, {5}]",
1457 descriptorName,
1458 numOutputChannels,
1459 weightTensorInfo.GetShape()[0],
1460 weightTensorInfo.GetShape()[1],
1461 weightTensorInfo.GetShape()[2],
1462 weightTensorInfo.GetShape()[3]));
1463 }
1464
1465 ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
1466
1467 Optional<TensorInfo> optionalBiasTensorInfo;
1468 if (m_Parameters.m_BiasEnabled)
1469 {
1470 optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
1471 const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
1472
1473 ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
1474 ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
1475 }
1476 ValidatePerAxisQuantization(inputTensorInfo,
1477 outputTensorInfo,
1478 weightTensorInfo,
1479 optionalBiasTensorInfo,
1480 descriptorName);
1481
1482 std::vector<DataType> supportedTypes =
1483 {
1490 };
1491
1492 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1493 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1494}
1495
1496void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1497{
1498 const std::string descriptorName{"PermuteQueueDescriptor"};
1499
1500 ValidateNumInputs(workloadInfo, descriptorName, 1);
1501 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1502
1503 const PermutationVector& mapping = m_Parameters.m_DimMappings;
1504
1505 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1506 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1507
1508 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
1509 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
1510
1511 for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
1512 {
1513 if (inputTensorInfo.GetShape()[i] != outputTensorInfo.GetShape()[mapping[i]])
1514 {
1515 throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(i) +
1516 " (=" + to_string(inputTensorInfo.GetShape()[i]) + ") " +
1517 "must match dst dimension " + to_string(mapping[i]) +
1518 " (=" + to_string(outputTensorInfo.GetShape()[mapping[i]]) + ")");
1519 }
1520 }
1521
1522 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1523}
1524
1526{
1527 const std::string descriptorName{"Pooling2dQueueDescriptor"};
1528
1529 ValidateNumInputs(workloadInfo, descriptorName, 1);
1530 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1531
1532 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1533 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1534
1535 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1536 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1537
1538 std::vector<DataType> supportedTypes =
1539 {
1546 };
1547
1548 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1549 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1550}
1551
1553{
1554 const std::string descriptorName{"Pooling3dQueueDescriptor"};
1555
1556 ValidateNumInputs(workloadInfo, descriptorName, 1);
1557 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1558
1559 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1560 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1561
1562 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 5, "input");
1563 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 5, "output");
1564
1565 std::vector<DataType> supportedTypes =
1566 {
1573 };
1574
1575 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1576 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1577}
1578
1579void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1580{
1581 const std::string descriptorName{"ResizeQueueDescriptor"};
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 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1590 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1591
1592 std::vector<DataType> supportedTypes =
1593 {
1601 };
1602
1603 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1604 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1605
1606 // Resize only changes width and height: batch and channel count must match.
1607 const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0];
1608 const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0];
1609 if (inputBatchSize != outputBatchSize)
1610 {
1612 fmt::format("{}: Input batch size ({}) does not match output batch size ({})",
1613 descriptorName, inputBatchSize, outputBatchSize));
1614 }
1615
1616 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1617 const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1618 const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()];
1619 if (inputChannelCount != outputChannelCount)
1620 {
1622 fmt::format("{}: Input channel count ({}) does not match output channel count ({})",
1623 descriptorName, inputChannelCount, outputChannelCount));
1624 }
1625}
1626
1628{
1629 const std::string descriptorName{"ReverseV2QueueDescriptor"};
1630
1631 // Backend restriction
1632 const unsigned int maxDimensions = 4;
1633
1634 ValidateNumInputs(workloadInfo, descriptorName, 2);
1635 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1636
1637 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1638 const TensorInfo& axisTensorInfo = workloadInfo.m_InputTensorInfos[1];
1639 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1640
1641 const auto inputTensorNumDimensions = inputTensorInfo.GetNumDimensions();
1642 if (inputTensorNumDimensions > maxDimensions)
1643 {
1644 throw InvalidArgumentException(descriptorName +
1645 ": Input tensors with rank greater than " +
1646 std::to_string(maxDimensions) + " are not supported.");
1647 }
1648
1649 const auto axisTensorNumDimensions = axisTensorInfo.GetNumDimensions();
1650 if (axisTensorNumDimensions > maxDimensions)
1651 {
1652 throw InvalidArgumentException(descriptorName +
1653 ": More than " + std::to_string(maxDimensions) + " axes cannot be specified.");
1654 }
1655
1656 if (axisTensorNumDimensions > inputTensorNumDimensions)
1657 {
1658 throw InvalidArgumentException(descriptorName +
1659 ": More axes specified than the number of axes on the input tensor.");
1660 }
1661
1662 std::vector<DataType> supportedTypes =
1663 {
1673 };
1674
1675 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1676
1677 std::vector<DataType> axisSupportedTypes =
1678 {
1680 };
1681
1682 ValidateDataTypes(axisTensorInfo, axisSupportedTypes, descriptorName);
1683
1684 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1685 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1686}
1687
1689{
1690 const std::string descriptorName{"FakeQuantizationQueueDescriptor"};
1691
1692 ValidateNumInputs(workloadInfo, descriptorName, 1);
1693 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1694
1695 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1696 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1697
1698 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 2, "input");
1699 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output");
1700
1701 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1702
1703 if (m_Parameters.m_Min > m_Parameters.m_Max)
1704 {
1705 throw InvalidArgumentException(descriptorName + ": min cannot be greater than max");
1706 }
1707}
1708
1710{
1711 const std::string descriptorName{"InstanceNormalizationQueueDescriptor"};
1712
1713 ValidateNumInputs(workloadInfo, descriptorName, 1);
1714 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1715
1716 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1717 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1718
1719 if (inputTensorInfo.GetNumDimensions() > 4)
1720 {
1721 throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1722 }
1723
1724 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1725
1726 // Check the supported data types
1727 std::vector<DataType> supportedTypes =
1728 {
1732 };
1733
1734 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1735 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1736}
1737
1739{
1740 const std::string descriptorName{"L2NormalizationQueueDescriptor"};
1741
1742 ValidateNumInputs(workloadInfo, descriptorName, 1);
1743 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1744
1745 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1746 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1747
1748 if (inputTensorInfo.GetNumDimensions() > 4)
1749 {
1750 throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
1751 }
1752
1753 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1754
1755 // Check the supported data types
1756 std::vector<DataType> supportedTypes =
1757 {
1764 };
1765
1766 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1767 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1768}
1769
1771{
1772 const std::string descriptorName{"LogSoftmaxQueueDescriptor"};
1773
1774 ValidateNumInputs(workloadInfo, descriptorName, 1);
1775 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1776
1777 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1778 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1779
1780 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1781
1782 std::vector<DataType> supportedTypes =
1783 {
1789 };
1790
1791 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1792 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1793}
1794
1796{
1797 const std::string descriptorName{"ConstantQueueDescriptor"};
1798
1799 ValidateNumInputs(workloadInfo, descriptorName, 0);
1800 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1801
1802 if (!m_LayerOutput)
1803 {
1804 throw InvalidArgumentException(descriptorName + ": No const input specified.");
1805 }
1806
1807 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1808 ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(), outputTensorInfo, descriptorName, "constant", "output");
1809
1810 // Check the supported data types
1811 std::vector<DataType> supportedTypes =
1812 {
1822 };
1823
1824 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1825}
1826
1827void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1828{
1829 const std::string descriptorName{"ReshapeQueueDescriptor"};
1830
1831 ValidateNumInputs(workloadInfo, descriptorName, 1);
1832 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1833
1834 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1835 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1836
1837 ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1838
1839 // Check the supported data types
1840 std::vector<DataType> supportedTypes =
1841 {
1850 };
1851
1852 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1853 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1854}
1855
1857{
1858 const std::string descriptorName{"SpaceToBatchNdQueueDescriptor"};
1859
1860 ValidateNumInputs(workloadInfo, descriptorName, 1);
1861 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1862
1863 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1864 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1865
1866 if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
1867 {
1868 throw InvalidArgumentException(descriptorName + ": Pad List must contain the same number of "
1869 "dimensions as Block Shape.");
1870 }
1871
1872 if (m_Parameters.m_BlockShape.size() == 2)
1873 {
1874 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1875 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1876 }
1877 else if (m_Parameters.m_BlockShape.size() == 1)
1878 {
1879 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 3, "input");
1880 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 3, "output");
1881 }
1882 else
1883 {
1884 throw InvalidArgumentException(descriptorName + ": Invalid Block and Crops size.");
1885 }
1886
1887 // Check input + padding and output have the same number of elements
1888 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1889 const unsigned int inputHeight = inputTensorInfo.GetShape()[dimensionIndices.GetHeightIndex()] +
1890 m_Parameters.m_PadList[0].first + m_Parameters.m_PadList[0].second;
1891 const unsigned int inputWidth = (inputTensorInfo.GetNumDimensions() == 3) ? 1 :
1892 inputTensorInfo.GetShape()[dimensionIndices.GetWidthIndex()] +
1893 m_Parameters.m_PadList[1].first + m_Parameters.m_PadList[1].second;
1894
1895 const int channelsIndex_int = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : -1;
1896 const unsigned int channelsIndex = channelsIndex_int < 0 ?
1897 static_cast<unsigned int>(channelsIndex_int) + inputTensorInfo.GetNumDimensions()
1898 : static_cast<unsigned int>(channelsIndex_int);
1899
1900 const unsigned int numInputElements = inputTensorInfo.GetShape()[0] *
1901 inputHeight *
1902 inputWidth *
1903 inputTensorInfo.GetShape()[channelsIndex];
1904
1905 if (outputTensorInfo.GetNumElements() != numInputElements)
1906 {
1907 throw InvalidArgumentException(descriptorName + ": Input tensor has " +
1908 to_string(numInputElements) + " after padding but output tensor has " +
1909 to_string(outputTensorInfo.GetNumElements()) + " elements.");
1910 }
1911
1912 // In a 4D tensor, there will be 2 spatialDimensions (H and W), and the for loop will run twice.
1913 // In a 3D tensor, there will be 1 spatialDimensions, and the for loop will run once.
1914 unsigned int firstSpatialDimension = m_Parameters.m_DataLayout == DataLayout::NCHW ? 2 : 1;
1915 for (unsigned int i = 0; i < m_Parameters.m_BlockShape.size(); ++i)
1916 {
1917 unsigned int spatialDimension = firstSpatialDimension + i;
1918 auto inputSize = inputTensorInfo.GetShape()[spatialDimension] +
1919 m_Parameters.m_PadList[i].first +
1920 m_Parameters.m_PadList[i].second;
1921 if (inputSize % m_Parameters.m_BlockShape[i] != 0)
1922 {
1923 throw InvalidArgumentException(descriptorName + ": Input dimension size after padding must be "
1924 "divisible by Block Shape in dimension: " + to_string(spatialDimension) + ".");
1925 }
1926 }
1927
1928 std::vector<DataType> supportedTypes =
1929 {
1936 };
1937
1938 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1939 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1940}
1941
1943{
1944 const std::string descriptorName{"SpaceToDepthQueueDescriptor"};
1945
1946 ValidateNumInputs(workloadInfo, descriptorName, 1);
1947 ValidateNumOutputs(workloadInfo, descriptorName, 1);
1948
1949 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
1950 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
1951
1952 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
1953 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
1954
1955 std::vector<DataType> supportedTypes =
1956 {
1965 };
1966
1967 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
1968 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
1969
1970 ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
1971
1972 if (m_Parameters.m_BlockSize == 0)
1973 {
1974 throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
1975 }
1976
1977 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
1978 const unsigned int wIndex = dimensionIndices.GetWidthIndex();
1979 const unsigned int hIndex = dimensionIndices.GetHeightIndex();
1980 const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
1981
1982 const TensorShape& inputShape = inputTensorInfo.GetShape();
1983 if (inputShape[hIndex] % m_Parameters.m_BlockSize != 0 || inputShape[wIndex] % m_Parameters.m_BlockSize != 0)
1984 {
1985 throw InvalidArgumentException(descriptorName + ": Input shape must be divisible "
1986 "by block size in all spatial dimensions");
1987 }
1988
1989 const TensorShape& outputShape = outputTensorInfo.GetShape();
1990 if (outputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
1991 {
1992 throw InvalidArgumentException(descriptorName + ": The depth of the output tensor"
1993 "must be divisible by the square of block size." );
1994 }
1995}
1996
1997void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1998{
1999 const std::string descriptorName{"FloorQueueDescriptor"};
2000
2001 ValidateNumInputs(workloadInfo, descriptorName, 1);
2002 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2003
2004 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2005 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2006
2007 std::vector<DataType> supportedTypes =
2008 {
2013 };
2014
2015 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2016 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2017 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2018 ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2019}
2020
2021void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2022{
2023 // ported from android/ml/nn/common/operations/LSTM.cpp CheckInputTensorDimensions()
2024
2025 const std::string descriptorName{"LstmQueueDescriptor"};
2026
2027 // check dimensions of all inputs and outputs
2028 if (workloadInfo.m_InputTensorInfos.size() != 3)
2029 {
2030 throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
2031 }
2032 if (workloadInfo.m_OutputTensorInfos.size() != 4)
2033 {
2034 throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
2035 }
2036
2037 std::vector<DataType> supportedTypes =
2038 {
2043 };
2044
2045 // check for supported type of one input and match them with all the other input and output
2046 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
2047
2048 // type matches all other inputs
2049 for (uint32_t i = 1u; i < workloadInfo.m_InputTensorInfos.size(); ++i)
2050 {
2051 ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
2052 workloadInfo.m_InputTensorInfos[i],
2053 descriptorName,
2054 "input_0",
2055 "input_" + std::to_string(i));
2056 }
2057 // type matches all other outputs
2058 for (uint32_t i = 0u; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
2059 {
2060 ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0],
2061 workloadInfo.m_OutputTensorInfos[i],
2062 "LstmQueueDescriptor",
2063 "input_0",
2064 "output_" + std::to_string(i));
2065 }
2066
2067 // Making sure clipping parameters have valid values.
2068 // == 0 means no clipping
2069 // > 0 means clipping
2070 if (m_Parameters.m_ClippingThresCell < 0.0f)
2071 {
2072 throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
2073 }
2074 if (m_Parameters.m_ClippingThresProj < 0.0f)
2075 {
2076 throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
2077 }
2078
2079 // Inferring batch size, number of outputs and number of cells from the inputs.
2080 const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[1];
2081 const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
2082 ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
2083 const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
2084 ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
2085 const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
2086
2087 // input tensor
2088 ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 2, (n_batch * n_input),
2089 descriptorName + " input_0");
2090 // outputStateInTensor
2091 ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
2092 descriptorName + " input_1");
2093 // outputStateInTensor
2094 ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
2095 descriptorName + " input_2");
2096 // scratchBufferTensor
2097 unsigned int scratchBufferSize = m_Parameters.m_CifgEnabled ? n_cell * 3 : n_cell * 4;
2098 ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[0], 2, (n_batch * scratchBufferSize),
2099 descriptorName + " output_0");
2100 // outputStateOutTensor
2101 ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[1], 2, (n_batch * n_output),
2102 descriptorName + " output_1");
2103 // cellStateOutTensor
2104 ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 2, (n_batch * n_cell),
2105 descriptorName + " output_2");
2106 // outputTensor
2107 ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[3], 2, (n_batch * n_output),
2108 descriptorName + " output_3");
2109
2110 // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
2112 {
2114 (n_cell * n_input), "InputLayerNormWeights");
2115 }
2116
2117 ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
2119 (n_cell * n_input), "InputToForgetWeights");
2120
2121 ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
2123 (n_cell * n_input), "InputToCellWeights");
2124
2126 {
2128 (n_cell * n_output), "RecurrentToInputWeights");
2129 }
2130
2131 ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
2133 (n_cell * n_output), "RecurrentToForgetWeights");
2134
2135 ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
2137 (n_cell * n_output), "RecurrentToCellWeights");
2138
2139 // Make sure the input-gate's parameters are either both present (regular
2140 // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
2141 bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
2142 !m_Parameters.m_CifgEnabled) ||
2144 m_Parameters.m_CifgEnabled));
2145 if (!cifg_weights_all_or_none)
2146 {
2147 throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
2148 "RecurrentToInputWeights must either both be present (regular LSTM) "
2149 "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
2150 "accordingly.");
2151 }
2152
2154 {
2156 n_cell, "CellToInputWeights");
2157 }
2159 {
2161 n_cell, "CellToForgetWeights");
2162 }
2164 {
2166 n_cell, "CellToOutputWeights");
2167 }
2168
2169 // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
2170 bool peephole_weights_all_or_none =
2172 && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
2174 && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
2175 if (!peephole_weights_all_or_none)
2176 {
2177 throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
2178 }
2179
2180 // Make sure the input gate bias is present only when not a CIFG-LSTM.
2181 if (m_Parameters.m_CifgEnabled)
2182 {
2183 if (m_InputGateBias)
2184 {
2185 throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
2186 }
2187 }
2188 else
2189 {
2190 if (!m_InputGateBias)
2191 {
2192 throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
2193 "must be present.");
2194 }
2195 ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1,
2196 n_cell, "InputGateBias");
2197 }
2198
2199 ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
2200 ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
2201
2202 ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
2203 ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
2204
2205 ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
2206 ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
2207
2209 {
2211 (n_cell * n_output), "ProjectionWeights");
2212 }
2213 if (m_ProjectionBias)
2214 {
2215 ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
2216 }
2217
2218 // Making sure the projection tensors are consistent:
2219 // 1) If projection weight is not present, then projection bias should not be
2220 // present.
2221 // 2) If projection weight is present, then projection bias is optional.
2222 bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
2223 !m_Parameters.m_ProjectionEnabled)
2225 m_Parameters.m_ProjectionEnabled)
2227 m_Parameters.m_ProjectionEnabled));
2228 if (!projecton_tensors_consistent)
2229 {
2230 throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
2231 }
2232
2233 // The four layer normalization weights either all have values or none of them have values. Additionally, if
2234 // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
2235 // either all have values or none of them have values. Layer normalization is used when the values of all the
2236 // layer normalization weights are present
2238 {
2239 ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
2240 }
2242 {
2243 ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2244 }
2246 {
2247 ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2248 }
2250 {
2251 ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2252 }
2253
2254 if (m_Parameters.m_LayerNormEnabled)
2255 {
2256 if (!m_Parameters.m_CifgEnabled)
2257 {
2259 {
2260 throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
2261 "disabled but InputLayerNormWeights are not present");
2262 }
2264 1, n_cell, "InputLayerNormWeights");
2265 }
2266 else if (m_InputLayerNormWeights)
2267 {
2268 throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
2269 "enabled");
2270 }
2271
2272 ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
2273 "ForgetLayerNormWeights");
2274 ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
2275
2276 ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
2277 "OutputLayerNormWeights");
2278 ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
2279
2280 ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
2281 "CellLayerNormWeights");
2282 ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
2283 }
2285 {
2286 throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
2287 "normalisation weights are present.");
2288 }
2289}
2290
2292{
2293 const std::string descriptorName{"ConvertFp32ToFp16QueueDescriptor"};
2294
2295 ValidateNumInputs(workloadInfo, descriptorName, 1);
2296 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2297
2298 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2299 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2300
2301 if (inputTensorInfo.GetDataType() != DataType::Float32)
2302 {
2303 throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32.");
2304 }
2305
2306 if (outputTensorInfo.GetDataType() != DataType::Float16)
2307 {
2308 throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float16.");
2309 }
2310
2311 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2312}
2313
2315{
2316 const std::string descriptorName{"ConvertFp16ToFp32QueueDescriptor"};
2317
2318 ValidateNumInputs(workloadInfo, descriptorName, 1);
2319 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2320
2321 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2322 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2323
2324 if (inputTensorInfo.GetDataType() != DataType::Float16)
2325 {
2326 throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float16.");
2327 }
2328
2329 if (outputTensorInfo.GetDataType() != DataType::Float32)
2330 {
2331 throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32.");
2332 }
2333
2334 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2335}
2336
2338{
2339 const std::string descriptorName{"DivisionQueueDescriptor"};
2340
2341 ValidateNumInputs(workloadInfo, descriptorName, 2);
2342 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2343
2344 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2345 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2346 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2347
2348 std::vector<DataType> supportedTypes =
2349 {
2357 };
2358
2359 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2360 ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2361 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2362
2363 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2364 inputTensorInfo1,
2365 outputTensorInfo,
2366 descriptorName,
2367 "input_0",
2368 "input_1");
2369}
2370
2372{
2373 const std::string descriptorName{"SubtractionQueueDescriptor"};
2374
2375 ValidateNumInputs(workloadInfo, descriptorName, 2);
2376 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2377
2378 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2379 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2380 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2381
2382 std::vector<DataType> supportedTypes =
2383 {
2391 };
2392
2393 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2394 ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2395 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2396
2397 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2398 inputTensorInfo1,
2399 outputTensorInfo,
2400 descriptorName,
2401 "input_0",
2402 "input_1");
2403}
2404
2405void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2406{
2407 const std::string descriptorName{"MaximumQueueDescriptor"};
2408
2409 ValidateNumInputs(workloadInfo, descriptorName, 2);
2410 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2411
2412 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2413 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2414 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2415
2416 std::vector<DataType> supportedTypes =
2417 {
2425 };
2426
2427 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2428 ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2429 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2430
2431 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2432 inputTensorInfo1,
2433 outputTensorInfo,
2434 descriptorName,
2435 "input_0",
2436 "input_1");
2437}
2438
2439void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2440{
2441 const std::string descriptorName{"MeanQueueDescriptor"};
2442
2443 ValidateNumInputs(workloadInfo, descriptorName, 1);
2444 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2445
2446 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2447 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2448
2449 std::vector<DataType> supportedTypes =
2450 {
2458 };
2459
2460 // First check if input tensor data type is supported, then
2461 // check if this data type matches the output tensor data type
2462 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2463 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2464
2465 if (m_Parameters.m_KeepDims)
2466 {
2467 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2468 }
2469 else if (m_Parameters.m_Axis.empty())
2470 {
2471 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
2472 }
2473 else
2474 {
2475 unsigned int outputDim =
2476 inputTensorInfo.GetNumDimensions() - armnn::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
2477 ValidateTensorNumDimensions(outputTensorInfo,
2478 descriptorName,
2479 outputDim > 0 ? outputDim : 1,
2480 "output");
2481 }
2482}
2483
2484void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2485{
2486 const std::string descriptorName{"PadQueueDescriptor"};
2487
2488 ValidateNumInputs(workloadInfo, descriptorName, 1);
2489 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2490
2491 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2492 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2493
2494 // input and output should have the same number of dimensions
2495 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output");
2496
2497 // there should be entry in the pad list for each dimension in the input tensor
2498 if (m_Parameters.m_PadList.size() != inputTensorInfo.GetNumDimensions()) {
2499 throw InvalidArgumentException(descriptorName + ":Pad List should contain the same number of entries "
2500 "as there are dimensions in the input tensor that is " +
2501 std::to_string(inputTensorInfo.GetNumDimensions()) + " entries " +
2502 " not " + std::to_string(m_Parameters.m_PadList.size()) + " entries.");
2503 }
2504}
2505
2507{
2508 const std::string descriptorName{"QuantizeQueueDescriptor"};
2509
2510 ValidateNumInputs(workloadInfo, descriptorName, 1);
2511 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2512
2513 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2514 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2515
2516 std::vector<DataType> supportedTypes =
2517 {
2525 };
2526
2527 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2528
2529 if (!IsQuantizedType(outputTensorInfo.GetDataType()))
2530 {
2531 throw InvalidArgumentException(descriptorName + ": Output of quantized layer must be quantized type.");
2532 }
2533}
2534
2536{
2537 const std::string descriptorName{"BatchToSpaceNdQueueDescriptor"};
2538
2539 ValidateNumInputs(workloadInfo, descriptorName, 1);
2540 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2541
2542 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2543 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2544
2545 if (m_Parameters.m_BlockShape.size() != m_Parameters.m_Crops.size())
2546 {
2547 throw InvalidArgumentException(descriptorName + ": Crops must contain the same number of "
2548 "dimensions as Block Shape.");
2549 }
2550
2551 if (m_Parameters.m_BlockShape.size() == 2)
2552 {
2553 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
2554 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
2555 }
2556 else if (m_Parameters.m_BlockShape.size() == 1)
2557 {
2558 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 3, "input");
2559 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 3, "output");
2560 }
2561 else
2562 {
2563 throw InvalidArgumentException(descriptorName + ": Invalid Block and Crops size.");
2564 }
2565
2566 // In a 4D tensor, there will be 2 spatialDimensions (H and W), and the for loop will run twice.
2567 // In a 3D tensor, there will be 1 spatialDimensions, and the for loop will run once.
2568 unsigned int firstSpatialDimension = m_Parameters.m_DataLayout == DataLayout::NCHW ? 2 : 1;
2569 for (unsigned int i = 0; i < m_Parameters.m_BlockShape.size(); ++i)
2570 {
2571 unsigned int spatialDimension = firstSpatialDimension + i;
2572 unsigned int cropSize = m_Parameters.m_Crops[i].first + m_Parameters.m_Crops[i].second;
2573 unsigned int outputSize = inputTensorInfo.GetShape()[spatialDimension] * m_Parameters.m_BlockShape[i];
2574 if (cropSize > outputSize)
2575 {
2576 throw InvalidArgumentException(descriptorName + ": CropSize must be less than or equal to the uncropped"
2577 "outputSize in dimension: " + to_string(spatialDimension) + ".");
2578 }
2579 }
2580
2581 std::vector<DataType> supportedTypes =
2582 {
2589 };
2590
2591 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2592 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2593}
2594
2596{
2597 const std::string descriptorName{"StridedSliceQueueDescriptor"};
2598
2599 ValidateNumInputs(workloadInfo, descriptorName, 1);
2600 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2601
2602 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2603 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2604
2605 std::vector<DataType> supportedTypes =
2606 {
2614 };
2615
2616 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2617 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2618
2619 ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2620
2621 const uint32_t rank = inputTensorInfo.GetNumDimensions();
2622 if (rank > 4)
2623 {
2624 throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported.");
2625 }
2626
2627 // Begin, End & Stride length must be of rank(input0)
2628 if (m_Parameters.m_Begin.size() != rank)
2629 {
2630 throw InvalidArgumentException(descriptorName + ": Begin length must be of rank " + std::to_string(rank));
2631 }
2632
2633 if (m_Parameters.m_End.size() != rank)
2634 {
2635 throw InvalidArgumentException(descriptorName + ": End length must be of rank " + std::to_string(rank));
2636 }
2637
2638 if (m_Parameters.m_Stride.size() != rank)
2639 {
2640 throw InvalidArgumentException(descriptorName + ": Stride length must be of rank " + std::to_string(rank));
2641 }
2642
2643 // Stride entries must be non-zero
2644 for (auto& stride : m_Parameters.m_Stride)
2645 {
2646 if (stride == 0)
2647 {
2648 throw InvalidArgumentException(descriptorName + ": Stride entries must be non-zero.");
2649 }
2650 }
2651}
2652
2653void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2654{
2655 const std::string descriptorName{"MinimumQueueDescriptor"};
2656
2657 ValidateNumInputs(workloadInfo, descriptorName, 2);
2658 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2659
2660 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2661 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2662 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2663
2664 std::vector<DataType> supportedTypes =
2665 {
2673 };
2674
2675 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
2676 ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
2677 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
2678
2679 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2680 inputTensorInfo1,
2681 outputTensorInfo,
2682 descriptorName,
2683 "input_0",
2684 "input_1");
2685}
2686
2687void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2688{
2689 const std::string descriptorName{"DebugQueueDescriptor"};
2690
2691 ValidateNumInputs(workloadInfo, descriptorName, 1);
2692 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2693}
2694
2695void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2696{
2697 const std::string descriptorName{"EqualQueueDescriptor"};
2698
2699 ValidateNumInputs(workloadInfo, descriptorName, 2);
2700 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2701
2702 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2703 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2704 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2705
2706 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2707 inputTensorInfo1,
2708 outputTensorInfo,
2709 descriptorName,
2710 "input_0",
2711 "input_1");
2712
2713 if (outputTensorInfo.GetDataType() != DataType::Boolean)
2714 {
2715 throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2716 }
2717}
2718
2719void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2720{
2721 const std::string descriptorName{"GreaterQueueDescriptor"};
2722
2723 ValidateNumInputs(workloadInfo, descriptorName, 2);
2724 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2725
2726 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2727 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2728 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2729
2730 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
2731 inputTensorInfo1,
2732 outputTensorInfo,
2733 descriptorName,
2734 "input_0",
2735 "input_1");
2736
2737 if (outputTensorInfo.GetDataType() != DataType::Boolean)
2738 {
2739 throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
2740 }
2741}
2742
2743void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2744{
2745 const std::string descriptorName{"RsqrtQueueDescriptor"};
2746
2747 ValidateNumInputs(workloadInfo, descriptorName, 1);
2748 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2749
2750 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2751 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2752
2753 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2754
2755 std::vector<DataType> supportedTypes =
2756 {
2763 };
2764
2765 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2766 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2767}
2768
2770{
2771 const std::string descriptorName{"GatherNdQueueDescriptor"};
2772
2773 ValidateNumInputs(workloadInfo, descriptorName, 2);
2774 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2775
2776 const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1];
2777 if (indicesTensorInfo.GetDataType() != DataType::Signed32)
2778 {
2779 throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32.");
2780 }
2781
2782 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2783 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2784
2785 std::vector<DataType> supportedTypes =
2786 {
2795 };
2796
2797 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2798
2799 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2800
2801 unsigned int outputDim = outputTensorInfo.GetNumDimensions();
2802 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output");
2803}
2804
2805void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2806{
2807 const std::string descriptorName{"GatherQueueDescriptor"};
2808
2809 ValidateNumInputs(workloadInfo, descriptorName, 2);
2810 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2811
2812 const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1];
2813 if (indicesTensorInfo.GetDataType() != DataType::Signed32)
2814 {
2815 throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32.");
2816 }
2817
2818 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2819 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2820
2821 std::vector<DataType> supportedTypes =
2822 {
2831 };
2832
2833 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2834
2835 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
2836
2837 unsigned int outputDim = inputTensorInfo.GetNumDimensions() + indicesTensorInfo.GetNumDimensions() - 1;
2838 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output");
2839}
2840
2842{
2843 const std::string& descriptorName{"DetectionPostProcessQueueDescriptor"};
2844
2845 ValidateNumInputs(workloadInfo, descriptorName, 2);
2846
2847 if (workloadInfo.m_OutputTensorInfos.size() != 4)
2848 {
2849 throw InvalidArgumentException(descriptorName + ": Requires exactly four outputs. " +
2850 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
2851 }
2852
2853 if (m_Anchors == nullptr)
2854 {
2855 throw InvalidArgumentException(descriptorName + ": Anchors tensor descriptor is missing.");
2856 }
2857
2858 const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
2859 const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
2860 const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
2861
2862 const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
2863 const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
2864 const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
2865 const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
2866
2867 ValidateTensorNumDimensions(boxEncodingsInfo, descriptorName, 3, "box encodings");
2868 ValidateTensorNumDimensions(scoresInfo, descriptorName, 3, "scores");
2869 ValidateTensorNumDimensions(anchorsInfo, descriptorName, 2, "anchors");
2870
2871 const std::vector<DataType> supportedInputTypes =
2872 {
2879 };
2880
2881 ValidateDataTypes(boxEncodingsInfo, supportedInputTypes, descriptorName);
2882 ValidateDataTypes(scoresInfo, supportedInputTypes, descriptorName);
2883 ValidateDataTypes(anchorsInfo, supportedInputTypes, descriptorName);
2884
2885 ValidateTensorNumDimensions(detectionBoxesInfo, descriptorName, 3, "detection boxes");
2886 ValidateTensorNumDimensions(detectionScoresInfo, descriptorName, 2, "detection scores");
2887 ValidateTensorNumDimensions(detectionClassesInfo, descriptorName, 2, "detection classes");
2888 ValidateTensorNumDimensions(numDetectionsInfo, descriptorName, 1, "num detections");
2889
2890 // NOTE: Output is always Float32 regardless of input type
2891 ValidateTensorDataType(detectionBoxesInfo, DataType::Float32, descriptorName, "detection boxes");
2892 ValidateTensorDataType(detectionScoresInfo, DataType::Float32, descriptorName, "detection scores");
2893 ValidateTensorDataType(detectionClassesInfo, DataType::Float32, descriptorName, "detection classes");
2894 ValidateTensorDataType(numDetectionsInfo, DataType::Float32, descriptorName, "num detections");
2895
2896 if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f)
2897 {
2898 throw InvalidArgumentException(descriptorName + ": Intersection over union threshold "
2899 "must be positive and less than or equal to 1.");
2900 }
2901
2902 if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
2903 {
2904 throw InvalidArgumentException(descriptorName + ": Number of classes with background "
2905 "should be equal to number of classes + 1.");
2906 }
2907}
2908
2910{
2911 const std::string& descriptorName{"DequantizeQueueDescriptor"};
2912
2913 ValidateNumInputs(workloadInfo, descriptorName, 1);
2914 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2915
2916 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2917 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2918
2919 std::vector<DataType> inputSupportedTypes =
2920 {
2926 };
2927 ValidateDataTypes(inputTensorInfo, inputSupportedTypes, descriptorName);
2928
2929 std::vector<DataType> outputSupportedTypes =
2930 {
2934 };
2935
2936 ValidateDataTypes(outputTensorInfo, outputSupportedTypes, descriptorName);
2937}
2938
2939void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2940{
2941 const std::string& descriptorName{"MergeQueueDescriptor"};
2942
2943 ValidateNumInputs(workloadInfo, descriptorName, 2);
2944 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2945
2946 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2947 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2948 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2949
2950 ValidateTensorShapesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2951 ValidateTensorShapesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2952
2953 ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1");
2954 ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output");
2955}
2956
2957void ShapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2958{
2959 const std::string& descriptorName{"ShapeQueueDescriptor"};
2960
2961 ValidateNumInputs(workloadInfo, descriptorName, 1);
2962 ValidateNumOutputs(workloadInfo, descriptorName, 1);
2963
2964 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
2965 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
2966
2967 std::vector<DataType> supportedTypes =
2968 {
2977 };
2978
2979 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
2980 ValidateDataTypes(outputTensorInfo, {DataType::Signed32}, descriptorName);
2981}
2982
2983void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
2984{
2985 const std::string& descriptorName{"SwitchQueueDescriptor"};
2986
2987 ValidateNumInputs(workloadInfo, descriptorName, 2);
2988 ValidateNumOutputs(workloadInfo, descriptorName, 2);
2989
2990 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
2991 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
2992
2993 const TensorInfo& outputTensorInfo0 = workloadInfo.m_OutputTensorInfos[0];
2994 const TensorInfo& outputTensorInfo1 = workloadInfo.m_OutputTensorInfos[1];
2995
2996 std::vector<DataType> supportedTypes =
2997 {
3003 };
3004
3005 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
3006 ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
3007
3008 ValidateDataTypes(outputTensorInfo0, supportedTypes, descriptorName);
3009 ValidateDataTypes(outputTensorInfo1, supportedTypes, descriptorName);
3010
3011 ValidateTensorShapesMatch(inputTensorInfo0,
3012 outputTensorInfo0,
3013 descriptorName,
3014 "input_0",
3015 "output_0");
3016
3017 ValidateTensorShapesMatch(inputTensorInfo0,
3018 outputTensorInfo1,
3019 descriptorName,
3020 "input_0",
3021 "output_1");
3022}
3023
3024void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& /*workloadInfo*/) const
3025{
3026 // This is internally generated, so it should not need validation.
3027}
3028
3029void PreluQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3030{
3031 const std::string& descriptorName{"PreluQueueDescriptor"};
3032
3033 ValidateNumInputs(workloadInfo, descriptorName, 2);
3034 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3035
3036 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3037 const TensorInfo& alphaTensorInfo = workloadInfo.m_InputTensorInfos[1];
3038 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3039
3040 std::vector<DataType> supportedTypes
3041 {
3048 };
3049
3050 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3051 ValidateDataTypes(alphaTensorInfo, supportedTypes, descriptorName);
3052
3053 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
3054
3055 ValidateTensorDataTypesMatch(inputTensorInfo, alphaTensorInfo, descriptorName, "input", "alpha");
3056 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "ouptut");
3057
3058 ValidateBroadcastTensorShapesMatch(inputTensorInfo,
3059 alphaTensorInfo,
3060 outputTensorInfo,
3061 descriptorName,
3062 "input",
3063 "alpha");
3064}
3065
3067{
3068 const std::string descriptorName{"TransposeConvolution2dQueueDescriptor"};
3069
3070 ValidateNumInputs(workloadInfo, descriptorName, 1);
3071 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3072
3073 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3074 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3075
3076 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input");
3077 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
3078
3079 ValidatePointer(m_Weight, descriptorName, "weight");
3080
3081 const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
3082 ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
3083
3084 ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
3085
3086 Optional<TensorInfo> optionalBiasTensorInfo;
3087 if (m_Parameters.m_BiasEnabled)
3088 {
3089 ValidatePointer(m_Bias, descriptorName, "bias");
3090
3091 optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
3092 const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
3093
3094 ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
3095 ValidateBiasTensorQuantization(biasTensorInfo, weightTensorInfo, descriptorName);
3096 }
3097
3098 ValidatePerAxisQuantization(inputTensorInfo,
3099 outputTensorInfo,
3100 weightTensorInfo,
3101 optionalBiasTensorInfo,
3102 descriptorName);
3103
3104 std::vector<DataType> supportedTypes =
3105 {
3112 };
3113
3114 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3115 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3116}
3117
3119{
3120 const std::string descriptorName{"TransposeQueueDescriptor"};
3121
3122 ValidateNumInputs(workloadInfo, descriptorName, 1);
3123 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3124
3125 const PermutationVector& mapping = m_Parameters.m_DimMappings;
3126
3127 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3128 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3129
3130 ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input");
3131 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output");
3132
3133 for (unsigned int i = 0u; i < mapping.GetSize(); ++i)
3134 {
3135 if (inputTensorInfo.GetShape()[mapping[i]] != outputTensorInfo.GetShape()[i])
3136 {
3137 throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(mapping[i]) +
3138 " (=" + to_string(inputTensorInfo.GetShape()[mapping[i]]) + ") " +
3139 "must match dst dimension " + to_string(i) +
3140 " (=" + to_string(outputTensorInfo.GetShape()[i]) + ")");
3141 }
3142 }
3143
3144 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3145}
3146
3148{
3149 const std::string descriptorName{"TransposeQueueDescriptor"};
3150
3151 ValidateNumInputs(workloadInfo, descriptorName, 1);
3152 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3153
3154 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3155 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3156
3157 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3158}
3159
3160void QLstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3161{
3162 const std::string descriptorName{"QLstmQueueDescriptor"};
3163
3164 // Validate number of inputs/outputs
3165 ValidateNumInputs(workloadInfo, descriptorName, 3);
3166 ValidateNumOutputs(workloadInfo, descriptorName, 3);
3167
3168 // Input/output tensor info
3169 auto inputInfo = workloadInfo.m_InputTensorInfos[0];
3170 auto outputStateInInfo = workloadInfo.m_InputTensorInfos[1];
3171 auto cellStateInInfo = workloadInfo.m_InputTensorInfos[2];
3172
3173 auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
3174 auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
3175 auto outputInfo = workloadInfo.m_OutputTensorInfos[2];
3176
3177 // Supported types for various tensors in QLSTM
3178 std::vector<DataType> inputOutputSupportedTypes =
3179 {
3181 };
3182
3183 std::vector<DataType> cellStateSupportedTypes =
3184 {
3186 };
3187
3188 std::vector<DataType> weightsSupportedTypes =
3189 {
3191 };
3192
3193 std::vector<DataType> layerNormPeepholeWeightsSupportedTypes =
3194 {
3196 };
3197
3198 std::vector<DataType> biasSupportedTypes =
3199 {
3201 };
3202
3203 // Validate types of input/output tensors
3204 ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3205 ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3206 ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3207
3208 ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3209 ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3210 ValidateDataTypes(outputInfo, inputOutputSupportedTypes, descriptorName);
3211
3212 // Validate matching types of input/output tensors
3213 ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3214 ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3215 "outputStateIn", "outputStateOut");
3216 ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3217
3218 // Infer number of batches, number of units, input size and output size from tensor dimensions
3219 const uint32_t numBatches = inputInfo.GetShape()[0];
3220 const uint32_t inputSize = inputInfo.GetShape()[1];
3221 const uint32_t outputSize = outputStateInInfo.GetShape()[1];
3222 const uint32_t numUnits = cellStateInInfo.GetShape()[1];
3223
3224 // Validate number of dimensions and number of elements for input/output tensors
3225 ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3226 ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3227 ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * numUnits), descriptorName + " cellStateIn");
3228
3229 ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3230 ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * numUnits), descriptorName + " cellStateOut");
3231 ValidateTensorNumDimNumElem(outputInfo, 2, (numBatches * outputSize), descriptorName + " output");
3232
3233 // Validate number of dimensions and number of elements for MANDATORY weight tensors
3234 ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3235 auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3236 ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (numUnits * inputSize), " InputToForgetWeights");
3237
3238 ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3239 auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3240 ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (numUnits * inputSize), " InputToCellWeights");
3241
3242 ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3243 auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3244 ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (numUnits * inputSize), " InputToOutputWeights");
3245
3246 ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3247 auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3248 ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (numUnits * outputSize),
3249 " RecurrentToForgetWeights");
3250
3251 ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3252 auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3253 ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3254
3255 ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3256 auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3257 ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights");
3258
3259 // Validate data types for MANDATORY weights tensors (all should match each other)
3260 ValidateDataTypes(inputToForgetWeightsInfo, weightsSupportedTypes, descriptorName);
3261
3262 ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToCellWeightsInfo, descriptorName,
3263 "inputToForgetWeights", "inputToCellWeights");
3264 ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3265 "inputToForgetWeights", "inputToOutputWeights");
3266
3267 ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3268 "inputToForgetWeights", "recurrentToForgeteights");
3269 ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3270 "inputToForgetWeights", "recurrentToCellWeights");
3271 ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3272 "inputToForgetWeights", "recurrentToOutputWeights");
3273
3274 // Validate number of dimensions and number of elements for MANDATORY bias tensors
3275 ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3276 auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3277 ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, numUnits, " ForgetGateBias");
3278
3279 ValidatePointer(m_CellBias, descriptorName, "CellBias");
3280 auto cellBiasInfo = m_CellBias->GetTensorInfo();
3281 ValidateTensorNumDimNumElem(cellBiasInfo, 1, numUnits, " CellBias");
3282
3283 ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3284 auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3285 ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, numUnits, " OutputGateBias");
3286
3287 // Validate data types for MANDATORY bias tensors
3288 ValidateDataTypes(forgetGateBiasInfo, biasSupportedTypes, descriptorName);
3289
3290 ValidateTensorDataTypesMatch(forgetGateBiasInfo, cellBiasInfo, descriptorName,
3291 "forgetGateBias", "cellBias");
3292 ValidateTensorDataTypesMatch(forgetGateBiasInfo, outputGateBiasInfo, descriptorName,
3293 "forgetGateBias", "outputGateBias");
3294
3295 // Validate OPTIONAL params: CIFG (inputToInputWeights, recurrentToInputWeights, inputGateBias)
3296 const bool allCifgParamsPresentOrNot = ((m_InputToInputWeights && m_RecurrentToInputWeights && m_InputGateBias &&
3297 !m_Parameters.m_CifgEnabled) ||
3299 !m_InputGateBias && m_Parameters.m_CifgEnabled));
3300
3301 if (!allCifgParamsPresentOrNot)
3302 {
3303 throw InvalidArgumentException(descriptorName +
3304 ": InputToInputWeights, RecurrentToInputWeights and InputGateBias must either all be present "
3305 "(CIFG disabled) or not be present at all (CIFG enabled). m_Parameters.m_CifgEnabled should be "
3306 "set appropriately.");
3307 }
3308
3309 if (!m_Parameters.m_CifgEnabled)
3310 {
3311 // Validate number of dimensions and number of elements
3312 auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3313 ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (numUnits * inputSize), " InputToInputWeights");
3314
3315 auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3316 ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (numUnits * outputSize),
3317 " RecurrentToInputWeights");
3318
3319 auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3320 ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, numUnits, " InputGateBias");
3321
3322 // Validate data types
3323 ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToInputWeightsInfo, descriptorName,
3324 "inputToForgetWeights", "inputToInputWeights");
3325 ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3326 "inputToForgetWeights", "recurrentToInputWeights");
3327 ValidateTensorDataTypesMatch(forgetGateBiasInfo, inputGateBiasInfo, descriptorName,
3328 "forgetGateBias", "inputGateBias");
3329 }
3330
3331 // Validate OPTIONAL params: Peephole (cellToInputWeights, cellToForgetWeights, cellToOutputWeights)
3332 bool allPeepholeWeightsPresentOrNot =
3334 && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
3336 && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
3337
3338 if (!allPeepholeWeightsPresentOrNot)
3339 {
3340 throw InvalidArgumentException(descriptorName +
3341 ": CellToInputWeights, CellToForgetWeights and CellToOutputWeights should all be present (Peephole "
3342 "enabled) or not be present at all (Peephole disabled). CellToInputWeights should only be present "
3343 "when Peephole is enabled and CIFG is disabled. m_Parameters.m_PeepholeEnabled should be set "
3344 "appropriately.");
3345 }
3346
3347 if (m_Parameters.m_PeepholeEnabled)
3348 {
3349 auto cellToForgetWeightsInfo = m_CellToForgetWeights->GetTensorInfo();
3350 ValidateTensorNumDimNumElem(cellToForgetWeightsInfo, 1, numUnits, " cellToForgetWeights");
3351 ValidateDataTypes(cellToForgetWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3352
3353 auto cellToOutputWeightsInfo = m_CellToOutputWeights->GetTensorInfo();
3354 ValidateTensorNumDimNumElem(cellToOutputWeightsInfo, 1, numUnits, " cellToOutputWeights");
3355 ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToOutputWeightsInfo, descriptorName,
3356 "cellToForgetWeight", "cellToOutputWeights");
3357
3358 if (!m_Parameters.m_CifgEnabled)
3359 {
3360 auto cellToInputWeightsInfo = m_CellToInputWeights->GetTensorInfo();
3361 ValidateTensorNumDimNumElem(cellToInputWeightsInfo, 1, numUnits, " cellToInputWeights");
3362 ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToInputWeightsInfo, descriptorName,
3363 "cellToForgetWeights", "cellToInputWeights");
3364 }
3365 }
3366
3367 // Validate OPTIONAL params: Layer Norm Weights
3368 bool allLayerNormWeightsPresentOrNot =
3372 && !m_OutputLayerNormWeights && !m_Parameters.m_LayerNormEnabled));
3373
3374 if (!allLayerNormWeightsPresentOrNot)
3375 {
3376 throw InvalidArgumentException(descriptorName +
3377 ": InputLayerNormWeights, ForgetLayerNormWeights, m_OutputLayerNormWeights "
3378 "and CellLayerNormWeights should all be present (Layer Norm enabled) or not "
3379 "be present at all (Layer Norm disabled). InputLayerNormWeights should "
3380 "only be present when Layer Norm is enabled and CIFG is disabled. "
3381 "m_Parameters.m_LayerNormEnabled should be set appropriately.");
3382 }
3383
3384 if (m_Parameters.m_LayerNormEnabled)
3385 {
3386 auto forgetLayerNormWeightsInfo = m_ForgetLayerNormWeights->GetTensorInfo();
3387 ValidateTensorNumDimNumElem(forgetLayerNormWeightsInfo, 1, numUnits, " forgetLayerNormWeights");
3388 ValidateDataTypes(forgetLayerNormWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName);
3389
3390 auto cellLayerNormWeightsInfo = m_CellLayerNormWeights->GetTensorInfo();
3391 ValidateTensorNumDimNumElem(cellLayerNormWeightsInfo, 1, numUnits, " cellLayerNormWeights");
3392 ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, cellLayerNormWeightsInfo, descriptorName,
3393 "forgetLayerNormWeights", "cellLayerNormWeights");
3394
3395 auto outputLayerNormWeightsInfo = m_OutputLayerNormWeights->GetTensorInfo();
3396 ValidateTensorNumDimNumElem(outputLayerNormWeightsInfo, 1, numUnits, " outputLayerNormWeights");
3397 ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, outputLayerNormWeightsInfo, descriptorName,
3398 "forgetLayerNormWeights", "outputLayerNormWeights");
3399
3400 if (!m_Parameters.m_CifgEnabled)
3401 {
3402 auto inputLayerNormWeightsInfo = m_InputLayerNormWeights->GetTensorInfo();
3403 ValidateTensorNumDimNumElem(inputLayerNormWeightsInfo, 1, numUnits, " inputLayerNormWeights");
3404 ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, inputLayerNormWeightsInfo, descriptorName,
3405 "forgetLayerNormWeights", "inputLayerNormWeights");
3406 }
3407 }
3408
3409 // Validate OPTIONAL params: Projection (projectionWeights, projectionBias)
3410 bool correctProjectionTensorsPresent =
3411 ((!m_ProjectionWeights && !m_ProjectionBias && !m_Parameters.m_ProjectionEnabled) ||
3412 (m_ProjectionWeights && !m_ProjectionBias && m_Parameters.m_ProjectionEnabled) ||
3413 (m_ProjectionWeights && m_ProjectionBias && m_Parameters.m_ProjectionEnabled));
3414
3415 if (!correctProjectionTensorsPresent)
3416 {
3417 throw InvalidArgumentException(descriptorName +
3418 ": If projection is enabled, ProjectionWeights should be present and "
3419 "ProjectionBias is optional. If projection is disabled, neither "
3420 "ProjectionWeights nor ProjectionBias should be present.");
3421 }
3422
3423 if (m_Parameters.m_ProjectionEnabled)
3424 {
3425 auto projectionWeightsInfo = m_ProjectionWeights->GetTensorInfo();
3426 ValidateTensorNumDimNumElem(projectionWeightsInfo, 2, (numUnits * outputSize), "ProjectionWeights");
3427 ValidateDataTypes(projectionWeightsInfo, weightsSupportedTypes, descriptorName);
3428
3429 if (m_ProjectionBias)
3430 {
3431 auto projectionBiasInfo = m_ProjectionBias->GetTensorInfo();
3432 ValidateTensorNumDimNumElem(projectionBiasInfo, 1, outputSize, "ProjectionBias");
3433 ValidateDataTypes(projectionBiasInfo, biasSupportedTypes, descriptorName);
3434 }
3435
3436 }
3437 else if ((outputInfo.GetQuantizationScale() != m_Parameters.m_HiddenStateScale) &&
3438 outputInfo.GetQuantizationOffset() != m_Parameters.m_HiddenStateZeroPoint) {
3439 throw InvalidArgumentException(descriptorName +
3440 ": If projection is disabled, output quantization info (scale, offset) "
3441 "should match HiddenStateScale and HiddenStateZeroPoint.");
3442 }
3443
3444}
3445
3447{
3448 const std::string descriptorName{"QuantizedLstmQueueDescriptor"};
3449
3450 // Validate number of inputs/outputs
3451 ValidateNumInputs(workloadInfo, descriptorName, 3);
3452 ValidateNumOutputs(workloadInfo, descriptorName, 2);
3453
3454 // Input/output tensor infos
3455 auto inputInfo = workloadInfo.m_InputTensorInfos[0];
3456 auto cellStateInInfo = workloadInfo.m_InputTensorInfos[1];
3457 auto outputStateInInfo = workloadInfo.m_InputTensorInfos[2];
3458
3459 auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[0];
3460 auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[1];
3461
3462 std::vector<DataType> inputOutputSupportedTypes =
3463 {
3465 };
3466
3467 std::vector<DataType> cellStateSupportedTypes =
3468 {
3470 };
3471
3472 std::vector<DataType> weightsSupportedTypes =
3473 {
3475 };
3476
3477 std::vector<DataType> biasSupportedTypes =
3478 {
3480 };
3481
3482 // Validate types of input/output tensors
3483 ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName);
3484 ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName);
3485 ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName);
3486
3487 ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName);
3488 ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName);
3489
3490 // Validate matching types of input/output tensors
3491 ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3492 ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName,
3493 "outputStateIn", "outputStateOut");
3494 ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3495
3496 // Validate matching quantization info for input/output tensors
3497 ValidateTensorQuantizationSpace(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn");
3498 ValidateTensorQuantizationSpace(inputInfo, outputStateOutInfo, descriptorName, "input", "outputStateOut");
3499 ValidateTensorQuantizationSpace(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut");
3500
3501 // Infer number of batches, input size and output size from tensor dimensions
3502 const uint32_t numBatches = inputInfo.GetShape()[0];
3503 const uint32_t inputSize = inputInfo.GetShape()[1];
3504 const uint32_t outputSize = cellStateInInfo.GetShape()[1];
3505
3506 // Validate number of dimensions and number of elements for input/output tensors
3507 ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input");
3508 ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * outputSize), descriptorName + " cellStateIn");
3509 ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn");
3510 ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * outputSize), descriptorName + " cellStateOut");
3511 ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut");
3512
3513 // Validate number of dimensions and number of elements for weights tensors
3514 ValidatePointer(m_InputToInputWeights, descriptorName, "InputToInputWeights");
3515 auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo();
3516 ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (outputSize * inputSize), " InputToInputWeights");
3517
3518 ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights");
3519 auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo();
3520 ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (outputSize * inputSize), " InputToForgetWeights");
3521
3522 ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights");
3523 auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo();
3524 ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (outputSize * inputSize), " InputToCellWeights");
3525
3526 ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights");
3527 auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo();
3528 ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (outputSize * inputSize), " InputToOutputWeights");
3529
3530 ValidatePointer(m_RecurrentToInputWeights, descriptorName, "RecurrentToInputWeights");
3531 auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo();
3532 ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToInputWeights");
3533
3534 ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights");
3535 auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo();
3536 ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (outputSize * outputSize),
3537 " RecurrentToForgetWeights");
3538
3539 ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights");
3540 auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo();
3541 ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3542
3543 ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights");
3544 auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo();
3545 ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights");
3546
3547 // Validate data types for weights tensors (all should match each other)
3548 ValidateDataTypes(inputToInputWeightsInfo, weightsSupportedTypes, descriptorName);
3549
3550 ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToForgetWeightsInfo, descriptorName,
3551 "inputToInputWeights", "inputToForgetWeights");
3552 ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToCellWeightsInfo, descriptorName,
3553 "inputToInputWeights", "inputToCellWeights");
3554 ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToOutputWeightsInfo, descriptorName,
3555 "inputToInputWeights", "inputToOutputWeights");
3556
3557 ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToInputWeightsInfo, descriptorName,
3558 "inputToInputWeights", "recurrentToInputWeights");
3559 ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToForgetWeightsInfo, descriptorName,
3560 "inputToInputWeights", "recurrentToForgeteights");
3561 ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToCellWeightsInfo, descriptorName,
3562 "inputToInputWeights", "recurrentToCellWeights");
3563 ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToOutputWeightsInfo, descriptorName,
3564 "inputToInputWeights", "recurrentToOutputWeights");
3565
3566 // Validate matching quantization info for weight tensors (all should match each other)
3567 ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToForgetWeightsInfo,
3568 descriptorName, "inputToInputWeights", "inputToForgetWeights");
3569 ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToCellWeightsInfo,
3570 descriptorName, "inputToInputWeights", "inputToCellWeights");
3571 ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToOutputWeightsInfo,
3572 descriptorName, "inputToInputWeights", "inputToOutputWeights");
3573
3574 ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToInputWeightsInfo,
3575 descriptorName, "inputToInputWeights", "recurrentToInputWeights");
3576 ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToForgetWeightsInfo,
3577 descriptorName, "inputToInputWeights", "recurrentToForgetWeights");
3578 ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToCellWeightsInfo,
3579 descriptorName, "inputToInputWeights", "recurrentToCellWeights");
3580 ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToOutputWeightsInfo,
3581 descriptorName, "inputToInputWeights", "recurrentToOutputWeights");
3582
3583 // Validate number of dimensions and number of elements in bias tensors
3584 ValidatePointer(m_InputGateBias, descriptorName, "InputGateBias");
3585 auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo();
3586 ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, outputSize, " InputGateBias");
3587
3588 ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias");
3589 auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo();
3590 ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, outputSize, " ForgetGateBias");
3591
3592 ValidatePointer(m_CellBias, descriptorName, "CellBias");
3593 auto cellBiasInfo = m_CellBias->GetTensorInfo();
3594 ValidateTensorNumDimNumElem(cellBiasInfo, 1, outputSize, " CellBias");
3595
3596 ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias");
3597 auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo();
3598 ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, outputSize, " OutputGateBias");
3599
3600 // Validate data types for bias tensors (all should match each other)
3601 ValidateDataTypes(inputGateBiasInfo, biasSupportedTypes, descriptorName);
3602
3603 ValidateTensorDataTypesMatch(inputGateBiasInfo, forgetGateBiasInfo, descriptorName,
3604 "inputGateBias", "forgetGateBias");
3605 ValidateTensorDataTypesMatch(inputGateBiasInfo, cellBiasInfo, descriptorName,
3606 "inputGateBias", "cellBias");
3607 ValidateTensorDataTypesMatch(inputGateBiasInfo, outputGateBiasInfo, descriptorName,
3608 "inputGateBias", "outputGateBias");
3609
3610 // Validate bias tensor quantization info
3611 ValidateBiasTensorQuantization(inputGateBiasInfo, inputToInputWeightsInfo, descriptorName);
3612 ValidateBiasTensorQuantization(forgetGateBiasInfo, inputToInputWeightsInfo, descriptorName);
3613 ValidateBiasTensorQuantization(cellBiasInfo, inputToInputWeightsInfo, descriptorName);
3614 ValidateBiasTensorQuantization(outputGateBiasInfo, inputToInputWeightsInfo, descriptorName);
3615}
3616
3617void AbsQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3618{
3619 const std::string descriptorName{"AbsQueueDescriptor"};
3620
3621 ValidateNumInputs(workloadInfo, descriptorName, 1);
3622 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3623
3624 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3625 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3626
3627 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3628
3629 std::vector<DataType> supportedTypes =
3630 {
3638 };
3639
3640 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3641 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3642}
3643
3644void SliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3645{
3646 const std::string descriptorName{"SliceQueueDescriptor"};
3647
3648 ValidateNumInputs(workloadInfo, descriptorName, 1);
3649 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3650
3651 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3652 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3653
3654 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3655
3656 const unsigned int rank = inputTensorInfo.GetNumDimensions();
3657 if (rank > 5)
3658 {
3659 throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 5 are not supported.");
3660 }
3661
3662 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, rank, "output");
3663
3664 // Check if m_Begin and m_Size have the expected length
3665 if (m_Parameters.m_Begin.size() != rank)
3666 {
3667 throw InvalidArgumentException(descriptorName +
3668 ": Length of begin offset descriptor must equal rank " + std::to_string(rank));
3669 }
3670 if (m_Parameters.m_Size.size() != rank)
3671 {
3672 throw InvalidArgumentException(descriptorName +
3673 ": Length of size descriptor must equal rank " + std::to_string(rank));
3674 }
3675
3676 // Check if the shape of the output tensor matches m_Size
3677 const TensorShape& outputShape = outputTensorInfo.GetShape();
3678 for (unsigned int i = 0u; i < rank; ++i)
3679 {
3680 if (m_Parameters.m_Size[i] != outputShape[i])
3681 {
3682 throw InvalidArgumentException(descriptorName + ": Size descriptor does not match output tensor.");
3683 }
3684 }
3685
3686 // Check if the sum of begin offset and size in a given dimension
3687 // does not exceed the size of corresponding input
3688 const TensorShape& inputShape = inputTensorInfo.GetShape();
3689 for(unsigned int i = 0u; i < rank; ++i)
3690 {
3691 if (m_Parameters.m_Begin[i] + m_Parameters.m_Size[i] > inputShape[i])
3692 {
3693 throw InvalidArgumentException(descriptorName + ": Sum of begin offset and size for dimension " +
3694 std::to_string(i) + " exceeds input size.");
3695 }
3696 }
3697}
3698
3700{
3701 const std::string descriptorName{"DepthToSpaceQueueDescriptor"};
3702
3703 ValidateNumInputs(workloadInfo, descriptorName, 1);
3704 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3705
3706 const TensorInfo& inputInfo = workloadInfo.m_InputTensorInfos[0];
3707 const TensorInfo& outputInfo = workloadInfo.m_OutputTensorInfos[0];
3708
3709 ValidateTensorNumDimensions(inputInfo, descriptorName, 4, "input");
3710 ValidateTensorNumDimensions(outputInfo, descriptorName, 4, "output");
3711
3712 std::vector<DataType> supportedTypes =
3713 {
3721 };
3722
3723 ValidateDataTypes(inputInfo, supportedTypes, descriptorName);
3724 ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
3725
3726 ValidateTensorNumElementsMatch(inputInfo, outputInfo, descriptorName, "input", "output");
3727
3728 if (m_Parameters.m_BlockSize == 0)
3729 {
3730 throw InvalidArgumentException(descriptorName + ": Block size cannot be 0.");
3731 }
3732
3733 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
3734 const unsigned int wIndex = dimensionIndices.GetWidthIndex();
3735 const unsigned int hIndex = dimensionIndices.GetHeightIndex();
3736 const unsigned int cIndex = dimensionIndices.GetChannelsIndex();
3737
3738 const TensorShape& outputShape = outputInfo.GetShape();
3739 if (outputShape[hIndex] % m_Parameters.m_BlockSize != 0 || outputShape[wIndex] % m_Parameters.m_BlockSize != 0)
3740 {
3741 throw InvalidArgumentException(descriptorName + ": Output width and height shape"
3742 "must be divisible by block size.");
3743 }
3744
3745 const TensorShape& inputShape = inputInfo.GetShape();
3746 if (inputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0)
3747 {
3748 throw InvalidArgumentException(descriptorName + ": The depth of the input tensor"
3749 "must be divisible by the square of block size." );
3750 }
3751}
3752
3754{
3755 const std::string descriptorName{"ComparisonQueueDescriptor"};
3756
3757 ValidateNumInputs(workloadInfo, descriptorName, 2);
3758 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3759
3760 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3761 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3762 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3763
3764 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3765 inputTensorInfo1,
3766 outputTensorInfo,
3767 descriptorName,
3768 "input_0",
3769 "input_1");
3770
3771 if (outputTensorInfo.GetDataType() != DataType::Boolean)
3772 {
3773 throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3774 }
3775}
3776
3778{
3779 const std::string descriptorName{"ElementwiseBinaryQueueDescriptor"};
3780
3781 ValidateNumInputs(workloadInfo, descriptorName, 2);
3782 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3783
3784 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3785 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3786 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3787
3788 std::vector<DataType> supportedTypes =
3789 {
3797 };
3798
3799 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
3800 ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName);
3801
3802 ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input", "output");
3803 ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input", "output");
3804}
3805
3807{
3808 const std::string descriptorName{"ElementwiseUnaryQueueDescriptor"};
3809
3810 ValidateNumInputs(workloadInfo, descriptorName, 1);
3811 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3812
3813 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3814 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3815
3816 ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3817
3818 std::vector<DataType> supportedTypes =
3819 {
3827 };
3828
3829 std::vector<DataType> logicalSupportedTypes =
3830 {
3832 };
3833
3834 if (m_Parameters.m_Operation == UnaryOperation::LogicalNot)
3835 {
3836 ValidateDataTypes(inputTensorInfo, logicalSupportedTypes, descriptorName);
3837 }
3838 else
3839 {
3840 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3841 }
3842
3843
3844 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3845}
3846
3847void RankQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3848{
3849 const std::string descriptorName{"RankQueueDescriptor"};
3850
3851 ValidateNumInputs(workloadInfo, descriptorName, 1);
3852 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3853
3854 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3855 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3856
3857 ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output");
3858 ValidateTensorNumElements(outputTensorInfo, descriptorName, 1, "output");
3859
3860 std::vector<DataType> supportedTypes =
3861 {
3870 };
3871
3872 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3873 ValidateDataTypes(outputTensorInfo, { DataType::Signed32 }, descriptorName);
3874}
3875
3877{
3878 const std::string descriptorName{"LogicalBinaryQueueDescriptor"};
3879
3880 ValidateNumInputs(workloadInfo, descriptorName, 2);
3881 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3882
3883 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
3884 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
3885 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3886
3887 ValidateBroadcastTensorShapesMatch(inputTensorInfo0,
3888 inputTensorInfo1,
3889 outputTensorInfo,
3890 descriptorName,
3891 "input_0",
3892 "input_1");
3893
3894 if (inputTensorInfo0.GetDataType() != DataType::Boolean)
3895 {
3896 throw InvalidArgumentException(descriptorName + ": Input tensor 0 type must be Boolean.");
3897 }
3898
3899 if (inputTensorInfo1.GetDataType() != DataType::Boolean)
3900 {
3901 throw InvalidArgumentException(descriptorName + ": Input tensor 1 type must be Boolean.");
3902 }
3903
3904 if (outputTensorInfo.GetDataType() != DataType::Boolean)
3905 {
3906 throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean.");
3907 }
3908}
3909
3910void ReduceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
3911{
3912 const std::string descriptorName{"ReduceQueueDescriptor"};
3913
3914 ValidateNumInputs(workloadInfo, descriptorName, 1);
3915 ValidateNumOutputs(workloadInfo, descriptorName, 1);
3916
3917 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
3918 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
3919
3920 std::vector<DataType> supportedTypes =
3921 {
3929 };
3930
3931 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
3932 ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
3933}
3934
3936{
3937 // Modified from LstmQueueDescriptor::Validate to support UnidirectionalSequenceLstm
3938
3939 const std::string descriptorName{"UnidirectionalSequenceLstmQueueDescriptor"};
3940
3941 // check dimensions of all inputs and outputs
3942 if (workloadInfo.m_InputTensorInfos.size() != 3)
3943 {
3944 throw InvalidArgumentException(descriptorName + ": Invalid number of inputs.");
3945 }
3946 if (workloadInfo.m_OutputTensorInfos.size() != 3)
3947 {
3948 throw InvalidArgumentException(descriptorName + ": Invalid number of outputs.");
3949 }
3950
3951 std::vector<DataType> supportedTypes =
3952 {
3955 };
3956
3957 // check for supported type of one input and match them with all the other input and output
3958 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName);
3959
3960 // Making sure clipping parameters have valid values.
3961 // == 0 means no clipping
3962 // > 0 means clipping
3963 if (m_Parameters.m_ClippingThresCell < 0.0f)
3964 {
3965 throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid");
3966 }
3967 if (m_Parameters.m_ClippingThresProj < 0.0f)
3968 {
3969 throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid");
3970 }
3971
3972 unsigned int batchIndx = 0;
3973 unsigned int inputIndx = 1;
3974 uint32_t timeStep = 1;
3975 unsigned int timeIndx = 1;
3976 inputIndx = 2;
3977 if (m_Parameters.m_TimeMajor)
3978 {
3979 batchIndx = 1;
3980 timeIndx = 0;
3981
3982 }
3983 timeStep = workloadInfo.m_InputTensorInfos[0].GetShape()[timeIndx];
3984
3985 // Inferring batch size, number of outputs and number of cells from the inputs.
3986 const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[inputIndx];
3987 const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[batchIndx];
3988 ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights");
3989 const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0];
3990 ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights");
3991 const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1];
3992
3993 // input tensor
3994 ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 3, (timeStep * n_batch * n_input),
3995 descriptorName + " input_0");
3996 // outputStateInTensor
3997 ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output),
3998 descriptorName + " input_1");
3999 // outputStateInTensor
4000 ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell),
4001 descriptorName + " input_2");
4002
4003 // outputTensor
4004 ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 3, (timeStep * n_batch * n_output),
4005 descriptorName + " output_0");
4006
4007 // check that dimensions of inputs/outputs and QueueDescriptor data match with each other
4009 {
4011 (n_cell * n_input), "InputLayerNormWeights");
4012 }
4013
4014 ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights");
4016 (n_cell * n_input), "InputToForgetWeights");
4017
4018 ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights");
4020 (n_cell * n_input), "InputToCellWeights");
4021
4023 {
4025 (n_cell * n_output), "RecurrentToInputWeights");
4026 }
4027
4028 ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights");
4030 (n_cell * n_output), "RecurrentToForgetWeights");
4031
4032 ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights");
4034 (n_cell * n_output), "RecurrentToCellWeights");
4035
4036 // Make sure the input-gate's parameters are either both present (regular
4037 // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly.
4038 bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights &&
4039 !m_Parameters.m_CifgEnabled) ||
4041 m_Parameters.m_CifgEnabled));
4042 if (!cifg_weights_all_or_none)
4043 {
4044 throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and "
4045 "RecurrentToInputWeights must either both be present (regular LSTM) "
4046 "or both not present (CIFG-LSTM). In addition CifgEnable must be set "
4047 "accordingly.");
4048 }
4049
4051 {
4053 n_cell, "CellToInputWeights");
4054 }
4056 {
4058 n_cell, "CellToForgetWeights");
4059 }
4061 {
4063 n_cell, "CellToOutputWeights");
4064 }
4065
4066 // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly.
4067 bool peephole_weights_all_or_none =
4069 && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled)
4071 && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled));
4072 if (!peephole_weights_all_or_none)
4073 {
4074 throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters.");
4075 }
4076
4077 // Make sure the input gate bias is present only when not a CIFG-LSTM.
4078 if (m_Parameters.m_CifgEnabled)
4079 {
4080 if (m_InputGateBias)
4081 {
4082 throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled.");
4083 }
4084 }
4085 else
4086 {
4087 if (!m_InputGateBias)
4088 {
4089 throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias "
4090 "must be present.");
4091 }
4092 ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1,
4093 n_cell, "InputGateBias");
4094 }
4095
4096 ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias");
4097 ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias");
4098
4099 ValidatePointer(m_CellBias, "Null pointer check", "CellBias");
4100 ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias");
4101
4102 ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias");
4103 ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias");
4104
4106 {
4108 (n_cell * n_output), "ProjectionWeights");
4109 }
4110 if (m_ProjectionBias)
4111 {
4112 ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias");
4113 }
4114
4115 // Making sure the projection tensors are consistent:
4116 // 1) If projection weight is not present, then projection bias should not be
4117 // present.
4118 // 2) If projection weight is present, then projection bias is optional.
4119 bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias &&
4120 !m_Parameters.m_ProjectionEnabled)
4122 m_Parameters.m_ProjectionEnabled)
4124 m_Parameters.m_ProjectionEnabled));
4125 if (!projecton_tensors_consistent)
4126 {
4127 throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent.");
4128 }
4129
4130 // The four layer normalization weights either all have values or none of them have values. Additionally, if
4131 // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights
4132 // either all have values or none of them have values. Layer normalization is used when the values of all the
4133 // layer normalization weights are present
4135 {
4136 ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights");
4137 }
4139 {
4140 ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
4141 }
4143 {
4144 ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
4145 }
4147 {
4148 ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
4149 }
4150
4151 if (m_Parameters.m_LayerNormEnabled)
4152 {
4153 if (!m_Parameters.m_CifgEnabled)
4154 {
4156 {
4157 throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is "
4158 "disabled but InputLayerNormWeights are not present");
4159 }
4161 1, n_cell, "InputLayerNormWeights");
4162 }
4163 else if (m_InputLayerNormWeights)
4164 {
4165 throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is "
4166 "enabled");
4167 }
4168
4169 ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled",
4170 "ForgetLayerNormWeights");
4171 ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights");
4172
4173 ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled",
4174 "OutputLayerNormWeights");
4175 ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights");
4176
4177 ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled",
4178 "CellLayerNormWeights");
4179 ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights");
4180 }
4182 {
4183 throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer "
4184 "normalisation weights are present.");
4185 }
4186}
4187
4189{
4190 const std::string descriptorName{"BatchMatMulDescriptor"};
4191
4192 ValidateNumInputs(workloadInfo, descriptorName, 2);
4193 ValidateNumOutputs(workloadInfo, descriptorName, 1);
4194
4195 // Inputs must be: both 2D+
4196 // For inputs X and Y whose dimensions to be multiplied are (M,N) and (I,J) respectively,
4197 // axes N and I must be the same size
4198
4199 const auto& inputXInfoBeforeParams = workloadInfo.m_InputTensorInfos[0];
4200 const auto& inputYInfoBeforeParams = workloadInfo.m_InputTensorInfos[1];
4201 const auto& outputInfo = workloadInfo.m_OutputTensorInfos[0];
4202 // Output info has already been inferred
4203
4204 std::vector<DataType> supportedTypes =
4205 {
4212 };
4213
4214 ValidateDataTypes(inputXInfoBeforeParams, supportedTypes, descriptorName);
4215 ValidateDataTypes(inputYInfoBeforeParams, supportedTypes, descriptorName);
4216 ValidateDataTypes(outputInfo, supportedTypes, descriptorName);
4217
4218 if ((inputXInfoBeforeParams.GetNumDimensions() < 2) ||
4219 (inputYInfoBeforeParams.GetNumDimensions() < 2))
4220 {
4221 throw InvalidArgumentException(descriptorName + ": Input tensors are not 2D or greater.");
4222 }
4223
4224 TensorInfo inputXInfoAfterParams;
4225 TensorInfo inputYInfoAfterParams;
4226
4227 if((m_Parameters.m_TransposeX && m_Parameters.m_AdjointX) ||
4228 (m_Parameters.m_TransposeY && m_Parameters.m_AdjointY))
4229 {
4230 throw InvalidArgumentException(descriptorName +
4231 ": Invalid descriptor parameters - Transpose and Adjoint "
4232 "cannot both be true for a given input tensor.");
4233 }
4234 if(m_Parameters.m_TransposeX)
4235 {
4236 inputXInfoAfterParams = armnnUtils::Permuted(inputXInfoBeforeParams,
4238 m_Parameters.m_DataLayoutX,
4239 inputXInfoBeforeParams.GetShape()));
4240 }
4241 else if(m_Parameters.m_AdjointX)
4242 {
4243 auto axesToMul = BatchMatMulDescriptor::GetAxesToMul(m_Parameters.m_DataLayoutX,
4244 inputXInfoBeforeParams.GetShape());
4245 if(inputXInfoBeforeParams.GetShape()[axesToMul.first] !=
4246 inputXInfoBeforeParams.GetShape()[axesToMul.second])
4247 {
4248 throw InvalidArgumentException(descriptorName +
4249 ": Adjoint is set to true for input tensor X, but the axes to be adjointed are not square." );
4250 }
4251 // Shape remains the same as it's square
4252 inputXInfoAfterParams = inputXInfoBeforeParams;
4253 }
4254 else
4255 {
4256 inputXInfoAfterParams = inputXInfoBeforeParams;
4257 }
4258
4259 if(m_Parameters.m_TransposeY)
4260 {
4261 inputYInfoAfterParams = armnnUtils::Permuted(inputYInfoBeforeParams,
4263 m_Parameters.m_DataLayoutY,
4264 inputYInfoBeforeParams.GetShape()));
4265 }
4266 else if(m_Parameters.m_AdjointY)
4267 {
4268 auto axesToMul = BatchMatMulDescriptor::GetAxesToMul(m_Parameters.m_DataLayoutY,
4269 inputYInfoBeforeParams.GetShape());
4270 if(inputYInfoBeforeParams.GetShape()[axesToMul.first] !=
4271 inputYInfoBeforeParams.GetShape()[axesToMul.second])
4272 {
4273 throw InvalidArgumentException(descriptorName +
4274 ": Adjoint is set to true for input tensor Y, but the axes to be adjointed are not square." );
4275 }
4276 // Shape remains the same as it's square
4277 inputYInfoAfterParams = inputYInfoBeforeParams;
4278 }
4279 else
4280 {
4281 inputYInfoAfterParams = inputYInfoBeforeParams;
4282 }
4283
4284 switch(m_Parameters.m_DataLayoutX)
4285 {
4286 case DataLayout::NCDHW:
4287 case DataLayout::NDHWC:
4288 if(inputXInfoAfterParams.GetNumDimensions() < 3)
4289 {
4290 throw InvalidArgumentException(descriptorName +
4291 ": Input tensor X does not have the correct "
4292 "number of dimensions for the Data Layout that it has been assigned.");
4293 }
4294 break;
4295 case DataLayout::NCHW:
4296 case DataLayout::NHWC:
4297 default:
4298 break;
4299 }
4300
4301 switch(m_Parameters.m_DataLayoutY)
4302 {
4303 case DataLayout::NCDHW:
4304 case DataLayout::NDHWC:
4305 if(inputYInfoAfterParams.GetNumDimensions() < 3)
4306 {
4307 throw InvalidArgumentException(descriptorName +
4308 ": Input tensor Y does not have the correct "
4309 "number of dimensions for the Data Layout that it has been assigned.");
4310 }
4311 break;
4312 case DataLayout::NCHW:
4313 case DataLayout::NHWC:
4314 default:
4315 break;
4316 }
4317
4318 auto axesXToMul = BatchMatMulDescriptor::GetAxesToMul(m_Parameters.m_DataLayoutX,
4319 inputXInfoAfterParams.GetShape());
4320 auto axesYToMul = BatchMatMulDescriptor::GetAxesToMul(m_Parameters.m_DataLayoutY,
4321 inputYInfoBeforeParams.GetShape());
4322
4323 if(inputXInfoAfterParams.GetShape()[axesXToMul.second]
4324 != inputYInfoAfterParams.GetShape()[axesYToMul.first])
4325 {
4326 throw InvalidArgumentException(descriptorName +
4327 ": The final axis of input tensor X must be the same size as "
4328 "the second last axis of input tensor Y.");
4329 }
4330
4331 { // Separate scope so we don't pollute the rest of the scope with our temp variables
4332 // e.g. NHWC isnt compatible with NCHW as of now
4333 DataLayout xLayout = m_Parameters.m_DataLayoutX;
4334 DataLayout yLayout = m_Parameters.m_DataLayoutY;
4335
4336 if(xLayout == DataLayout::NCHW || xLayout == DataLayout::NCDHW)
4337 {
4338 if(yLayout == DataLayout::NHWC || yLayout == DataLayout::NDHWC)
4339 {
4340 throw InvalidArgumentException(descriptorName +
4341 ": Invalid input tensor data layout combination.");
4342 }
4343 }
4344 if(yLayout == DataLayout::NCHW || yLayout == DataLayout::NCDHW)
4345 {
4346 if(xLayout == DataLayout::NHWC || xLayout == DataLayout::NDHWC)
4347 {
4348 throw InvalidArgumentException(descriptorName +
4349 ": Invalid input tensor data layout combination.");
4350 }
4351 }
4352 }
4353
4354 // Simulate aligning the ends of the matrix dims and prepending 1's to the beginning of the shorter one
4355 unsigned int outputTensorDimSize = std::max(inputXInfoAfterParams.GetNumDimensions(),
4356 inputYInfoAfterParams.GetNumDimensions());
4357 if(outputTensorDimSize-2 > 0)
4358 {
4359 TensorInfo tiXNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4361 TensorInfo tiYNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4363 TensorInfo tiOutNotMul = TensorInfo(TensorShape(outputTensorDimSize-2),
4365
4366 auto doAxisExtension = [&](std::vector<unsigned int> axisIndices, TensorInfo& ti)
4367 {
4368 auto sizeDiff = (outputTensorDimSize-2) - axisIndices.size();
4369
4370 for(unsigned int i = 0; i < sizeDiff; i++)
4371 {
4372 axisIndices.insert(axisIndices.begin(), 1);
4373 }
4374
4375 for(unsigned int i = 0; i < ti.GetNumDimensions(); i++)
4376 {
4377 ti.GetShape()[i] = inputXInfoAfterParams.GetShape()[i];
4378 }
4379 };
4380
4381 auto axesXNotMul = BatchMatMulDescriptor::GetAxesNotMul(m_Parameters.m_DataLayoutX,
4382 inputXInfoAfterParams.GetShape());
4383 auto axesYNotMul = BatchMatMulDescriptor::GetAxesNotMul(m_Parameters.m_DataLayoutY,
4384 inputYInfoAfterParams.GetShape());
4385
4386 doAxisExtension(axesXNotMul, tiXNotMul);
4387 doAxisExtension(axesYNotMul, tiYNotMul);
4388
4389 for(unsigned int i = 0; i < tiOutNotMul.GetNumDimensions(); i++)
4390 {
4391 tiOutNotMul.GetShape()[i] = std::max(tiXNotMul.GetShape()[i],
4392 tiYNotMul.GetShape()[i]);
4393 }
4394
4395 ValidateBroadcastTensorShapesMatch(tiXNotMul,
4396 tiYNotMul,
4397 tiOutNotMul,
4398 descriptorName,
4399 "input_X",
4400 "input_Y");
4401 }
4402}
4403
4404void TileQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
4405{
4406 const std::string& descriptorName{"TileQueueDescriptor"};
4407
4408 ValidateNumInputs(workloadInfo, descriptorName, 1);
4409 ValidateNumOutputs(workloadInfo, descriptorName, 1);
4410
4411 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
4412 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
4413
4414 std::vector<DataType> supportedTypes =
4415 {
4424 };
4425
4426 // Multiples length must be the same as the number of dimensions in input.
4427 if (m_Parameters.m_Multiples.size() != inputTensorInfo.GetNumDimensions())
4428 {
4429 throw InvalidArgumentException(descriptorName +
4430 ": Multiples length is not same as the number of dimensions in Input.");
4431 }
4432
4433 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
4434 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
4435}
4436
4438{
4439 const std::string& descriptorName{"BroadcastToQueueDescriptor"};
4440
4441 ValidateNumInputs(workloadInfo, descriptorName, 1);
4442 ValidateNumOutputs(workloadInfo, descriptorName, 1);
4443
4444 const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
4445 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
4446
4447 std::vector<DataType> supportedTypes =
4448 {
4457 };
4458
4459 ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
4460 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
4461}
4462
4464{
4465 const std::string& descriptorName{"ScatterQueueDescriptor"};
4466
4467 ValidateNumInputs(workloadInfo, descriptorName, 3);
4468 ValidateNumOutputs(workloadInfo, descriptorName, 1);
4469
4470 const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0];
4471 const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1];
4472 const TensorInfo& inputTensorInfo2 = workloadInfo.m_InputTensorInfos[2];
4473 const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
4474
4475 std::vector<DataType> supportedTypes =
4476 {
4484 };
4485
4486 std::vector<DataType> indicesSupportedTypes =
4487 {
4489 };
4490
4491 if (m_Parameters.m_InputEnabled)
4492 {
4493 ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName);
4494 }
4495 else
4496 {
4497 ValidateDataTypes(inputTensorInfo0, indicesSupportedTypes, descriptorName);
4498 }
4499
4500 ValidateDataTypes(inputTensorInfo1, indicesSupportedTypes, descriptorName);
4501 ValidateDataTypes(inputTensorInfo2, supportedTypes, descriptorName);
4502 ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName);
4503}
4504
4505} // namespace armnn
#define CHECK_LOCATION()
bool has_value() const noexcept
Definition Optional.hpp:53
SizeType GetSize() const
Definition Types.hpp:359
float GetQuantizationScale() const
Definition Tensor.cpp:461
const TensorShape & GetShape() const
Definition Tensor.hpp:193
unsigned int GetNumDimensions() const
Definition Tensor.hpp:197
bool IsTypeSpaceMatch(const TensorInfo &other) const
Check that the types are the same and, if quantize, that the quantization parameters are the same.
Definition Tensor.cpp:432
int32_t GetQuantizationOffset() const
Definition Tensor.cpp:482
bool IsQuantized() const
Definition Tensor.cpp:508
unsigned int GetNumElements() const
Definition Tensor.hpp:198
Optional< unsigned int > GetQuantizationDim() const
Definition Tensor.cpp:498
std::vector< float > GetQuantizationScales() const
Definition Tensor.cpp:451
bool HasPerAxisQuantization() const
Definition Tensor.cpp:446
DataType GetDataType() const
Definition Tensor.hpp:200
bool HasMultipleQuantizationScales() const
Definition Tensor.hpp:203
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition Tensor.cpp:174
Provides access to the appropriate indexes for Channels, Height and Width based on DataLayout.
unsigned int GetHeightIndex() const
unsigned int GetChannelsIndex() const
Copyright (c) 2021 ARM Limited and Contributors.
constexpr bool IsQuantized8BitType(DataType dataType)
Optional< T > MakeOptional(Args &&... args)
Utility template that constructs an object of type T in-place and wraps it inside an Optional<T> obje...
Definition Optional.hpp:305
constexpr const char * GetDataTypeName(DataType dataType)
constexpr bool IsQuantizedType()
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
DataType GetBiasDataType(DataType inputDataType)
DataLayout
Definition Types.hpp:63
DataType
Definition Types.hpp:49
armnn::TensorShape Permuted(const armnn::TensorShape &srcShape, const armnn::PermutationVector &mappings)
Definition Permute.cpp:125
unsigned int GetUnsignedAxis(const unsigned int inputDimension, const int axis)
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
static std::pair< unsigned int, unsigned int > GetAxesToMul(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the two axes (for each input) for multiplication.
static PermutationVector GetPermuteVec(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the axes which will be transposed.
static std::vector< unsigned int > GetAxesNotMul(DataLayout dataLayout, const TensorShape &tensorShape)
Static helper to get the axes (for each input) that will not be multiplied together.
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< unsigned int > m_Origin
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< ViewOrigin > m_ViewOrigins
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_LayerOutput
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
const ConstTensorHandle * m_Anchors
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
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
const ConstTensorHandle * m_OutputLayerNormWeights
const ConstTensorHandle * m_InputToOutputWeights
const ConstTensorHandle * m_InputLayerNormWeights
const ConstTensorHandle * m_CellToForgetWeights
const ConstTensorHandle * m_RecurrentToInputWeights
const ConstTensorHandle * m_ForgetGateBias
const ConstTensorHandle * m_ProjectionWeights
const ConstTensorHandle * m_InputGateBias
const ConstTensorHandle * m_RecurrentToOutputWeights
const ConstTensorHandle * m_OutputGateBias
const ConstTensorHandle * m_CellBias
const ConstTensorHandle * m_InputToCellWeights
const ConstTensorHandle * m_CellToInputWeights
const ConstTensorHandle * m_CellToOutputWeights
const ConstTensorHandle * m_InputToForgetWeights
const ConstTensorHandle * m_InputToInputWeights
const ConstTensorHandle * m_RecurrentToCellWeights
const ConstTensorHandle * m_ProjectionBias
const ConstTensorHandle * m_ForgetLayerNormWeights
const ConstTensorHandle * m_RecurrentToForgetWeights
const ConstTensorHandle * m_CellLayerNormWeights
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
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
const ConstTensorHandle * m_OutputLayerNormWeights
const ConstTensorHandle * m_InputToOutputWeights
const ConstTensorHandle * m_InputLayerNormWeights
const ConstTensorHandle * m_CellToForgetWeights
const ConstTensorHandle * m_RecurrentToInputWeights
const ConstTensorHandle * m_ForgetGateBias
const ConstTensorHandle * m_ProjectionWeights
const ConstTensorHandle * m_InputGateBias
const ConstTensorHandle * m_RecurrentToOutputWeights
const ConstTensorHandle * m_OutputGateBias
const ConstTensorHandle * m_CellBias
const ConstTensorHandle * m_InputToCellWeights
const ConstTensorHandle * m_CellToInputWeights
const ConstTensorHandle * m_CellToOutputWeights
const ConstTensorHandle * m_InputToForgetWeights
const ConstTensorHandle * m_InputToInputWeights
const ConstTensorHandle * m_RecurrentToCellWeights
const ConstTensorHandle * m_ProjectionBias
const ConstTensorHandle * m_ForgetLayerNormWeights
const ConstTensorHandle * m_RecurrentToForgetWeights
const ConstTensorHandle * m_CellLayerNormWeights
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
const ConstTensorHandle * m_InputToOutputWeights
const ConstTensorHandle * m_RecurrentToInputWeights
const ConstTensorHandle * m_ForgetGateBias
const ConstTensorHandle * m_InputGateBias
const ConstTensorHandle * m_RecurrentToOutputWeights
const ConstTensorHandle * m_OutputGateBias
const ConstTensorHandle * m_CellBias
const ConstTensorHandle * m_InputToCellWeights
const ConstTensorHandle * m_InputToForgetWeights
const ConstTensorHandle * m_InputToInputWeights
const ConstTensorHandle * m_RecurrentToCellWeights
const ConstTensorHandle * m_RecurrentToForgetWeights
void ValidateTensorNumDimensions(const TensorInfo &tensor, std::string const &descName, unsigned int numDimensions, std::string const &tensorName) const
std::vector< ITensorHandle * > m_Inputs
std::vector< ITensorHandle * > m_Outputs
void ValidateInputsOutputs(const std::string &descName, unsigned int numExpectedIn, unsigned int numExpectedOut) const
void ValidateTensorNumDimNumElem(const TensorInfo &tensorInfo, unsigned int numDimension, unsigned int numElements, std::string const &tensorName) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
void Validate(const WorkloadInfo &workloadInfo) const
std::vector< ViewOrigin > m_ViewOrigins
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
Contains information about TensorInfos of a layer.
std::vector< TensorInfo > m_OutputTensorInfos
std::vector< TensorInfo > m_InputTensorInfos