blob: c94fa25ac2e767ffc1bcca23a6a336bb2d5b9876 [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
5#include "WorkloadData.hpp"
6
7#include "CpuTensorHandle.hpp"
telsoa014fcda012018-03-09 14:13:49 +00008
Matteo Martincigh21350152018-11-28 16:22:22 +00009#include <DataLayoutIndexed.hpp>
Matthew Bentham8800c002018-11-19 13:19:28 +000010
telsoa014fcda012018-03-09 14:13:49 +000011#include <algorithm>
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +000012#include <iomanip>
telsoa014fcda012018-03-09 14:13:49 +000013#include <string>
14#include <sstream>
telsoa014fcda012018-03-09 14:13:49 +000015
16#include <boost/format.hpp>
Aron Virginas-Tard4f0fea2019-04-09 14:08:06 +010017#include <boost/numeric/conversion/cast.hpp>
telsoa014fcda012018-03-09 14:13:49 +000018
Matteo Martincigh21350152018-11-28 16:22:22 +000019using namespace armnnUtils;
20
telsoa014fcda012018-03-09 14:13:49 +000021namespace armnn
22{
23
24//---------------------------------------------------------------
25DataType GetBiasDataType(DataType inputDataType)
26{
27 switch (inputDataType)
28 {
telsoa01c577f2c2018-08-31 09:22:23 +010029 case DataType::Float16:
30 return DataType::Float16;
telsoa014fcda012018-03-09 14:13:49 +000031 case DataType::Float32:
32 return DataType::Float32;
33 case DataType::QuantisedAsymm8:
34 return DataType::Signed32;
Ruomei Yan88d44b82019-05-23 14:29:06 +010035 case DataType::QuantisedSymm16:
36 return DataType::Signed32;
telsoa014fcda012018-03-09 14:13:49 +000037 default:
38 BOOST_ASSERT_MSG(false, "Invalid input data type");
39 return DataType::Float32;
40 }
41}
42
43namespace
44{
45
46//---------------------------------------------------------------
47//android ndk does not support std::to_string function.
48template <typename T>
49std::string to_string(T value)
50{
51 std::ostringstream os;
52 os << value;
53 return os.str();
54}
55
56//---------------------------------------------------------------
57void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName)
58{
59 if (!ptr)
60 {
61 throw InvalidArgumentException(descName + ": Invalid null pointer. The " +
62 paramName + " parameter must be set.");
63 }
64}
65
66//---------------------------------------------------------------
67void ValidateTensorShapesMatch(const TensorInfo& first,
68 const TensorInfo& second,
69 std::string const& descName,
70 std::string const& firstName,
71 std::string const& secondName)
72{
73 if (first.GetShape() != second.GetShape())
74 {
75 throw InvalidArgumentException(descName + ": "
76 + firstName + " & " + secondName + " must have identical shapes");
77 }
78}
79
80//---------------------------------------------------------------
Sadik Armaganeff363d2019-04-05 15:25:46 +010081void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000082{
Sadik Armaganeff363d2019-04-05 15:25:46 +010083 if (workloadInfo.m_InputTensorInfos.size() != expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000084 {
85 throw InvalidArgumentException(descName +
Sadik Armaganeff363d2019-04-05 15:25:46 +010086 ": Requires exactly " + to_string(expectedSize) + "input(s). " +
telsoa014fcda012018-03-09 14:13:49 +000087 to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided.");
88 }
89}
90
91//---------------------------------------------------------------
Sadik Armaganeff363d2019-04-05 15:25:46 +010092void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000093{
Sadik Armaganeff363d2019-04-05 15:25:46 +010094 if (workloadInfo.m_OutputTensorInfos.size() != expectedSize)
telsoa014fcda012018-03-09 14:13:49 +000095 {
96 throw InvalidArgumentException(descName +
Sadik Armaganeff363d2019-04-05 15:25:46 +010097 ": Requires exactly " + to_string(expectedSize) + " output(s). " +
telsoa014fcda012018-03-09 14:13:49 +000098 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
99 }
100}
101
102//---------------------------------------------------------------
103void ValidateTensorNumDimensions(const TensorInfo& tensor,
104 std::string const& descName,
105 unsigned int numDimensions,
106 std::string const& tensorName)
107{
108 if (tensor.GetNumDimensions() != numDimensions)
109 {
110 throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " +
111 to_string(tensor.GetNumDimensions()) + " dimensions for " +
112 tensorName + " tensor.");
113 }
114}
115
116//---------------------------------------------------------------
117void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType,
118 const std::string& descName, std::string const& tensorName)
119{
120 if (tensor.GetDataType() != dataType)
121 {
122 throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " +
123 GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor.");
124 }
125}
126
127//---------------------------------------------------------------
128void ValidateBiasTensorQuantization(const TensorInfo& biasTensor, const TensorInfo& inputTensorInfo,
129 const TensorInfo& weightsTensorInfo, const std::string& descName)
130{
131 if (biasTensor.GetQuantizationOffset() != 0)
132 {
133 throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " +
134 to_string(biasTensor.GetQuantizationOffset()));
135 }
136 const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightsTensorInfo.GetQuantizationScale();
kevmay016c46dd32018-12-17 15:32:45 +0000137 if (std::abs(biasTensor.GetQuantizationScale() - expectedScale) > 0.00000001f)
telsoa014fcda012018-03-09 14:13:49 +0000138 {
139 // Print the float values with extra precision to see very small differences
140 std::stringstream msg;
141 msg << std::setprecision(10) << descName << ": Expected " << expectedScale <<
142 " quantization scale for bias tensor (the product of the input and weight scales), but got " <<
143 biasTensor.GetQuantizationScale();
144 throw InvalidArgumentException(msg.str());
145 }
146}
147
148//---------------------------------------------------------------
149void ValidateTensors(const std::vector<ITensorHandle*>& vec,
150 unsigned int numExpected,
151 const std::string& descName,
152 const std::string& varName)
153{
154 if (vec.empty() && numExpected > 0)
155 {
156 throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array.");
157 }
158
159 for (unsigned int i = 0; i < numExpected; ++i)
160 {
161 if (!vec[i])
162 {
163 throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i));
164 }
165 }
166}
167
168//---------------------------------------------------------------
169void ValidateBroadcastTensorShapesMatch(const TensorInfo& first,
170 const TensorInfo& second,
171 const TensorInfo& output,
172 std::string const& descName,
173 std::string const& firstName,
174 std::string const& secondName)
175{
176 // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get
177 // broadcasted.
178 if (first.GetNumDimensions() != second.GetNumDimensions())
179 {
180 throw InvalidArgumentException(descName + ": Tensors "
181 + firstName + " & " + secondName
182 + " must have the same number of dimensions in order to be broadcasted");
183 }
184 uint32_t numDims = first.GetNumDimensions();
185 std::vector<uint32_t> outputDims(numDims, 0u);
186 for (uint32_t i = 0; i < numDims; i++)
187 {
188 const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i];
189 const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1);
190 if (dimsNotEqual && dimsNotOne)
191 {
192 throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes");
193 }
194 outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]);
195 }
196 TensorShape broadcastShape = TensorShape(boost::numeric_cast<unsigned int>(outputDims.size()), outputDims.data());
197 if (broadcastShape != output.GetShape())
198 {
199 throw InvalidArgumentException(descName + ": The tensor shape resulting from adding "
200 + firstName + " & " + secondName
201 + " does not match the output shape");
202 }
203}
204
205//---------------------------------------------------------------
206/// Validates that the output tensor's quantization scale is greater than the product
207/// of the two input tensors' quantization scales. This is a requirement of the implementation of
208/// the quantized multiplication.
209void ValidateTensorQuantizationMultiplier(const TensorInfo& inputTensor1, const TensorInfo& inputTensor2,
210 const TensorInfo& outputTensorInfo, std::string const& descName,
211 const std::string& inputTensor1Name, const std::string& inputTensor2Name, const std::string& outputTensorName)
212{
213 if (outputTensorInfo.GetDataType() == DataType::QuantisedAsymm8)
214 {
215 if (outputTensorInfo.GetQuantizationScale() <=
216 inputTensor1.GetQuantizationScale() * inputTensor2.GetQuantizationScale())
217 {
218 std::stringstream msg;
219 msg << descName << ": Quantization scale of " << outputTensorName << " is not greater than " <<
220 "the product of the " << inputTensor1Name << " and " << inputTensor2Name << " tensors";
221 throw InvalidArgumentException(msg.str());
222 }
223 }
224}
225
Sadik Armaganeff363d2019-04-05 15:25:46 +0100226//---------------------------------------------------------------
227void ValidateDataTypes(const TensorInfo& info,
228 const std::vector<armnn::DataType>& supportedTypes,
229 std::string const& descName)
230{
231 auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType());
232 if (iterator == supportedTypes.end())
233 {
234 throw InvalidArgumentException(descName + ": " + " Tensor type is not supported.");
235 }
236}
237
telsoa014fcda012018-03-09 14:13:49 +0000238} //namespace
239
240void QueueDescriptor::ValidateInputsOutputs(const std::string& descName,
241 unsigned int numExpectedIn, unsigned int numExpectedOut) const
242{
243 ValidateTensors(m_Inputs, numExpectedIn, descName, "input");
244 ValidateTensors(m_Outputs, numExpectedOut, descName, "output");
245}
246
247//---------------------------------------------------------------
248void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
249{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100250 ValidateNumInputs(workloadInfo, "MemCopyQueueDescriptor", 1);
251 ValidateNumOutputs(workloadInfo, "MemCopyQueueDescriptor" , 1);
telsoa014fcda012018-03-09 14:13:49 +0000252
253 if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size())
254 {
255 throw InvalidArgumentException(boost::str(
256 boost::format("Number of input infos (%1%) does not match the number of output infos (%2%)")
257 % workloadInfo.m_InputTensorInfos.size() % workloadInfo.m_OutputTensorInfos.size()));
258 }
259
260 for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
261 {
262 if (workloadInfo.m_InputTensorInfos[i].GetNumElements() !=
263 workloadInfo.m_OutputTensorInfos[i].GetNumElements())
264 {
265 throw InvalidArgumentException(boost::str(
266 boost::format("Number of elements for tensor input and output %1% does not match")
267 % i ));
268 }
269 }
270
271 if (m_Inputs.size() != m_Outputs.size())
272 {
273 throw InvalidArgumentException(boost::str(
274 boost::format("Number of inputs (%1%) does not match the number of outputs (%2%)")
275 % m_Inputs.size() % m_Outputs.size()));
276 }
277
278 for (unsigned int i = 0; i < m_Inputs.size(); ++i)
279 {
280 if (!m_Inputs[i])
281 {
282 throw InvalidArgumentException(boost::str(boost::format("Invalid null input %1%") % i));
283 }
284
285 if (!m_Outputs[i])
286 {
287 throw InvalidArgumentException(boost::str(boost::format("Invalid null output %1%") % i));
288 }
289 }
290}
291
292//---------------------------------------------------------------
293void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
294{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100295 ValidateNumInputs(workloadInfo, "ActivationQueueDescriptor", 1);
296 ValidateNumOutputs(workloadInfo, "ActivationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000297 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
298 workloadInfo.m_OutputTensorInfos[0],
299 "ActivationQueueDescriptor",
300 "input",
301 "output");
Nattapat Chaimanowongae2c5f02019-04-24 16:19:57 +0100302
303 std::vector<DataType> supportedTypes = {
304 DataType::Float32,
305 DataType::Float16,
Teresa Charlin18515e22019-04-24 10:17:46 +0100306 DataType::QuantisedAsymm8,
307 DataType::QuantisedSymm16
Nattapat Chaimanowongae2c5f02019-04-24 16:19:57 +0100308 };
309
310 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
311 supportedTypes,
312 "ActivationQueueDescriptor");
313
314 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
315 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
316 "ActivationQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000317}
318
319//---------------------------------------------------------------
320void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
321{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100322 ValidateNumInputs(workloadInfo, "SoftmaxQueueDescriptor", 1);
323 ValidateNumOutputs(workloadInfo, "SoftmaxQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000324
325 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
326 workloadInfo.m_OutputTensorInfos[0],
327 "SoftmaxQueueDescriptor",
328 "input",
329 "output");
nikraj01248683f2019-05-29 16:46:50 +0100330
331 std::vector<DataType> supportedTypes =
332 {
333 DataType::Float16,
334 DataType::Float32,
335 DataType::QuantisedAsymm8,
336 DataType::QuantisedSymm16
337 };
338
339 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
340 supportedTypes,
341 "SoftmaxQueueDescriptor");
342
343 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
344 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
345 "SoftmaxQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000346}
347
348//---------------------------------------------------------------
349void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
350{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100351 ValidateNumInputs(workloadInfo, "SplitterQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000352
Ruomei Yan25339c32019-05-28 16:48:20 +0100353 // Check the supported data types
354 std::vector<DataType> supportedTypes =
355 {
356 DataType::Float32,
357 DataType::Float16,
358 DataType::Boolean,
359 DataType::Signed32,
360 DataType::QuantisedAsymm8,
361 DataType::QuantisedSymm16
362 };
363
364 for (unsigned long i = 0; i < workloadInfo.m_OutputTensorInfos.size(); ++i)
365 {
366 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[i],
367 supportedTypes,
368 "SplitterQueueDescriptor");
369 }
370 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
371 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
372 "SplitterQueueDescriptor");
373
telsoa014fcda012018-03-09 14:13:49 +0000374 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
375 {
376 throw InvalidArgumentException("SplitterQueueDescriptor: At least one output needs to be provided.");
377 }
378
379 if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size())
380 {
381 throw InvalidArgumentException(
382 "SplitterQueueDescriptor: Number of split windows "
383 "has to match number of workloadInfo.m_OutputTensorInfos. "
384 "Number of windows: " +
385 to_string(m_ViewOrigins.size()) +
386 ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size()));
387 }
388
telsoa01c577f2c2018-08-31 09:22:23 +0100389 //The dimensionality of all the windows has to match the dimensionality (not shape) of the input.
telsoa014fcda012018-03-09 14:13:49 +0000390 std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions();
391 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
392 {
telsoa01c577f2c2018-08-31 09:22:23 +0100393 //Checks that the dimensionality of input is same as the split windows.
telsoa014fcda012018-03-09 14:13:49 +0000394 ViewOrigin const& e = m_ViewOrigins[w];
395 if (e.m_Origin.size() != inputDims)
396 {
397 throw InvalidArgumentException("SplitterQueueDescriptor: Window origin have to "
398 "have the same dimensionality as the input tensor. "
399 "Window origin (index: " +
400 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
401 " dimensions, the input "
402 "tensor has " +
403 to_string(inputDims) + " dimensions.");
404 }
405 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
406 {
407 if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] >
408 workloadInfo.m_InputTensorInfos[0].GetShape()[i])
409 {
410 throw InvalidArgumentException("SplitterQueueDescriptor: Window extent coordinates have to "
411 "be smaller or equal than the size of the input in that coord.");
412 }
413 }
414 }
415}
416
417//---------------------------------------------------------------
Jim Flynne242f2d2019-05-22 14:24:13 +0100418void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
telsoa014fcda012018-03-09 14:13:49 +0000419{
Jim Flynne242f2d2019-05-22 14:24:13 +0100420 ValidateNumOutputs(workloadInfo, "ConcatQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000421
422 if (m_Inputs.size() <= 0)
423 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100424 throw InvalidArgumentException("ConcatQueueDescriptor: At least one input needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000425 }
426 if (m_Outputs.size() <= 0)
427 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100428 throw InvalidArgumentException("ConcatQueueDescriptor: At least one output needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000429 }
430
431 if (workloadInfo.m_InputTensorInfos.size() <= 0)
432 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100433 throw InvalidArgumentException("ConcatQueueDescriptor: At least one TensorInfo input needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000434 }
435 if (workloadInfo.m_OutputTensorInfos.size() <= 0)
436 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100437 throw InvalidArgumentException("ConcatQueueDescriptor: At least one TensorInfo output needs to be provided.");
telsoa014fcda012018-03-09 14:13:49 +0000438 }
439
Nikhil Raj8599a412018-11-19 14:51:07 +0000440 if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions())
441 {
442 throw InvalidArgumentException("Invalid Concatenation Axis provided");
443 }
444
445 if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1)
446 {
447 return;
448 }
449
telsoa014fcda012018-03-09 14:13:49 +0000450 if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size())
451 {
452 throw InvalidArgumentException(
Jim Flynne242f2d2019-05-22 14:24:13 +0100453 "ConcatQueueDescriptor: Number of split windows "
telsoa014fcda012018-03-09 14:13:49 +0000454 "has to match number of workloadInfo.m_InputTensorInfos. "
455 "Number of windows: " +
456 to_string(m_ViewOrigins.size()) +
457 ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size()));
458 }
459
telsoa01c577f2c2018-08-31 09:22:23 +0100460 //The dimensionality of all the windows has to match the dimensionality (not shape) of the output.
telsoa014fcda012018-03-09 14:13:49 +0000461 std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions();
462 for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w )
463 {
telsoa01c577f2c2018-08-31 09:22:23 +0100464 //Checks that the dimensionality of output is same as the split windows.
telsoa014fcda012018-03-09 14:13:49 +0000465 ViewOrigin const& e = m_ViewOrigins[w];
466 if (e.m_Origin.size() != outputDims)
467 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100468 throw InvalidArgumentException("ConcatQueueDescriptor: Window origin have to "
telsoa014fcda012018-03-09 14:13:49 +0000469 "have the same dimensionality as the output tensor. "
470 "Window origin (index: " +
471 to_string(w) + ") has " + to_string(e.m_Origin.size()) +
472 " dimensions, the output "
473 "tensor has " +
474 to_string(outputDims) + " dimensions.");
475 }
telsoa01c577f2c2018-08-31 09:22:23 +0100476 //Checks that the merge windows are within the output tensor.
telsoa014fcda012018-03-09 14:13:49 +0000477 for (unsigned int i = 0; i < e.m_Origin.size(); ++i)
478 {
479 if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i]
480 > workloadInfo.m_OutputTensorInfos[0].GetShape()[i])
481 {
Jim Flynne242f2d2019-05-22 14:24:13 +0100482 throw InvalidArgumentException("ConcatQueueDescriptor: Window extent coordinates have to "
telsoa014fcda012018-03-09 14:13:49 +0000483 "be smaller or equal than the size of the output in that coord.");
484 }
485 }
486 }
Jim Flynncbb66aa2019-05-15 13:03:54 +0100487
488 // Check the supported data types
489 std::vector<DataType> supportedTypes =
490 {
491 DataType::Float32,
492 DataType::Float16,
493 DataType::Boolean,
494 DataType::Signed32,
495 DataType::QuantisedAsymm8,
496 DataType::QuantisedSymm16
497 };
498
499 for (unsigned long i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i)
500 {
501 ValidateDataTypes(workloadInfo.m_InputTensorInfos[i],
502 supportedTypes,
Jim Flynne242f2d2019-05-22 14:24:13 +0100503 "ConcatQueueDescriptor");
Jim Flynncbb66aa2019-05-15 13:03:54 +0100504 }
505 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
506 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
Jim Flynne242f2d2019-05-22 14:24:13 +0100507 "ConcatQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000508}
509
510//---------------------------------------------------------------
511void FullyConnectedQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
512{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100513 ValidateNumInputs(workloadInfo, "FullyConnectedQueueDescriptor", 1);
514 ValidateNumOutputs(workloadInfo, "FullyConnectedQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000515 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "FullyConnectedQueueDescriptor", 2, "output");
516
517 if (!(workloadInfo.m_InputTensorInfos[0].GetNumDimensions() == 2 ||
518 workloadInfo.m_InputTensorInfos[0].GetNumDimensions() == 4))
519 {
520 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Input tensor must have 2 or 4 dimensions.");
521 }
522
523 if (m_Weight == nullptr)
524 {
525 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Weight tensor descriptor is missing.");
526 }
527
528 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "FullyConnectedQueueDescriptor", 2, "weight");
529
530 if (m_Parameters.m_BiasEnabled)
531 {
532 if (m_Bias == nullptr)
533 {
534 throw InvalidArgumentException("FullyConnectedQueueDescriptor: Bias is enabled but "
535 "bias value tensor descriptor is missing.");
536 }
537
telsoa01c577f2c2018-08-31 09:22:23 +0100538 // Validates type and quantization values.
telsoa014fcda012018-03-09 14:13:49 +0000539 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
540 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "FullyConnectedQueueDescriptor");
541
542 ValidateTensorDataType(m_Bias->GetTensorInfo(),
543 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
544 "FullyConnectedQueueDescriptor", "bias");
545
546 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "FullyConnectedQueueDescriptor", 1, "bias");
547 }
548
549 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
550 workloadInfo.m_OutputTensorInfos[0], "FullyConnectedQueueDescriptor", "input", "weights", "output");
Francis Murtagh46c09d02019-05-28 08:15:28 +0100551
552 // Check the supported data types
553 std::vector<DataType> supportedTypes =
554 {
555 DataType::Float32,
556 DataType::Float16,
557 DataType::QuantisedAsymm8,
558 DataType::QuantisedSymm16
559 };
560
561 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
562 supportedTypes,
563 "FullyConnectedQueueDescriptor");
564
565 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
566 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
567 "FullyConnectedQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000568}
569
570//---------------------------------------------------------------
571void NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
572{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100573 ValidateNumInputs(workloadInfo, "NormalizationQueueDescriptor", 1);
574 ValidateNumOutputs(workloadInfo, "NormalizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000575 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
576 workloadInfo.m_OutputTensorInfos[0],
577 "NormalizationQueueDescriptor",
578 "input",
579 "output");
580}
581
582void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
583{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100584 ValidateNumInputs(workloadInfo, "AdditionQueueDescriptor", 2);
585 ValidateNumOutputs(workloadInfo, "AdditionQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000586
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100587 std::vector<DataType> supportedTypes = {
588 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +0100589 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +0100590 DataType::QuantisedSymm16,
591 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100592 };
593
594 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
595 supportedTypes,
596 "AdditionQueueDescriptor");
597
598 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
599 supportedTypes,
600 "AdditionQueueDescriptor");
601
602 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
603 supportedTypes,
604 "AdditionQueueDescriptor");
605
telsoa014fcda012018-03-09 14:13:49 +0000606 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
607 workloadInfo.m_InputTensorInfos[1],
608 workloadInfo.m_OutputTensorInfos[0],
609 "AdditionQueueDescriptor",
610 "first input",
611 "second input");
telsoa014fcda012018-03-09 14:13:49 +0000612}
613
614//---------------------------------------------------------------
615void MultiplicationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
616{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100617 ValidateNumInputs(workloadInfo, "MultiplicationQueueDescriptor", 2);
618 ValidateNumOutputs(workloadInfo, "MultiplicationQueueDescriptor", 1);
surmeh01bceff2f2018-03-29 16:29:27 +0100619
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100620 std::vector<DataType> supportedTypes = {
621 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +0100622 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +0100623 DataType::QuantisedSymm16,
624 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +0100625 };
626
627 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
628 supportedTypes,
629 "MultiplicationQueueDescriptor");
630
631 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
632 supportedTypes,
633 "MultiplicationQueueDescriptor");
634
635 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
636 supportedTypes,
637 "MultiplicationQueueDescriptor");
638
surmeh01bceff2f2018-03-29 16:29:27 +0100639 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
640 workloadInfo.m_InputTensorInfos[1],
641 workloadInfo.m_OutputTensorInfos[0],
642 "MultiplicationQueueDescriptor",
643 "first input",
644 "second input");
telsoa014fcda012018-03-09 14:13:49 +0000645}
646
647void BatchNormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
648{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100649 ValidateNumInputs(workloadInfo, "BatchNormalizationQueueDescriptor", 1);
650 ValidateNumOutputs(workloadInfo, "BatchNormalizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000651 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
652 workloadInfo.m_OutputTensorInfos[0],
653 "BatchNormalizationQueueDescriptor",
654 "input",
655 "output");
656 ValidatePointer(m_Mean, "BatchNormalizationQueueDescriptor", "mean");
657 ValidatePointer(m_Variance, "BatchNormalizationQueueDescriptor", "variance");
658 ValidatePointer(m_Beta, "BatchNormalizationQueueDescriptor", "beta");
659 ValidatePointer(m_Gamma, "BatchNormalizationQueueDescriptor", "gamma");
660
661
662 ValidateTensorNumDimensions(m_Mean->GetTensorInfo(), "BatchNormalizationQueueDescriptor", 1, "mean");
663 ValidateTensorNumDimensions(m_Variance->GetTensorInfo(), "BatchNormalizationQueueDescriptor", 1, "variance");
664 ValidateTensorNumDimensions(m_Beta->GetTensorInfo(), "BatchNormalizationQueueDescriptor", 1, "beta");
665 ValidateTensorNumDimensions(m_Gamma->GetTensorInfo(), "BatchNormalizationQueueDescriptor", 1, "gamma");
666
667 ValidateTensorShapesMatch(
668 m_Mean->GetTensorInfo(), m_Variance->GetTensorInfo(), "BatchNormalizationQueueDescriptor", "mean", "variance");
669 ValidateTensorShapesMatch(
670 m_Mean->GetTensorInfo(), m_Beta->GetTensorInfo(), "BatchNormalizationQueueDescriptor", "mean", "beta");
671 ValidateTensorShapesMatch(
672 m_Mean->GetTensorInfo(), m_Gamma->GetTensorInfo(), "BatchNormalizationQueueDescriptor", "mean", "gamma");
673}
674
675void Convolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
676{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100677 ValidateNumInputs(workloadInfo, "Convolution2dQueueDescriptor", 1);
678 ValidateNumOutputs(workloadInfo, "Convolution2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000679
680 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "Convolution2dQueueDescriptor", 4, "input");
681 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "Convolution2dQueueDescriptor", 4, "output");
682
683 ValidatePointer(m_Weight, "Convolution2dQueueDescriptor", "weight");
684 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "Convolution2dQueueDescriptor", 4, "weight");
685 ValidateTensorDataType(m_Weight->GetTensorInfo(), workloadInfo.m_InputTensorInfos[0].GetDataType(),
686 "Convolution2dQueueDescriptor", "weight");
687 if (m_Parameters.m_BiasEnabled)
688 {
689 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "Convolution2dQueueDescriptor", 1, "bias");
690 ValidateTensorDataType(m_Bias->GetTensorInfo(),
691 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
692 "Convolution2dQueueDescriptor", "bias");
693 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
694 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "Convolution2dQueueDescriptor");
695 }
696
697 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
698 workloadInfo.m_OutputTensorInfos[0], "Convolution2dQueueDescriptor", "input", "weights", "output");
699}
700
701void DepthwiseConvolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
702{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100703 ValidateNumInputs(workloadInfo, "DepthwiseConvolution2dQueueDescriptor", 1);
704 ValidateNumOutputs(workloadInfo, "DepthwiseConvolution2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000705
706 ValidateTensorNumDimensions(
707 workloadInfo.m_InputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", 4, "input");
708 ValidateTensorNumDimensions(
709 workloadInfo.m_OutputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", 4, "output");
710
711 ValidatePointer(m_Weight, "DepthwiseConvolution2dQueueDescriptor", "weight");
712 ValidateTensorNumDimensions(m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 4, "weight");
713
Bruno Goncalves22972f02019-04-26 21:03:24 -0300714 if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 )
715 {
716 throw InvalidArgumentException(
717 boost::str(boost::format("DepthwiseConvolution2dQueueDescriptor: dilationX (provided %1%) "
718 "and dilationY (provided %2%) cannot be smaller than 1.")
719 % m_Parameters.m_DilationX % m_Parameters.m_DilationX));
720 }
721
Nikhil Rajcec6b652018-10-12 13:51:57 +0100722 const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3;
723
Matteo Martincigh747ef822018-12-18 09:26:39 +0000724 // Expected weight shape: [ M, I, H, W ] - This shape does NOT depend on the data layout
725 // inputChannels * channelMultiplier should be equal to outputChannels.
telsoa014fcda012018-03-09 14:13:49 +0000726 const unsigned int numWeightChannelMultiplier = m_Weight->GetTensorInfo().GetShape()[0];
Matteo Martincigh747ef822018-12-18 09:26:39 +0000727 const unsigned int numWeightInputChannels = m_Weight->GetTensorInfo().GetShape()[1];
Nikhil Rajcec6b652018-10-12 13:51:57 +0100728 const unsigned int numWeightOutputChannels = workloadInfo.m_OutputTensorInfos[0].GetShape()[channelIndex];
telsoa014fcda012018-03-09 14:13:49 +0000729 if (numWeightChannelMultiplier * numWeightInputChannels != numWeightOutputChannels)
730 {
731 throw InvalidArgumentException(
732 boost::str(boost::format("DepthwiseConvolution2dQueueDescriptor: output_channels (provided %1%) should be "
733 "equal to input_channels (provided %2%) multiplied by channel_multiplier "
734 "(provided %3%).")
735 % numWeightOutputChannels % numWeightInputChannels % numWeightChannelMultiplier));
736 }
737
738 if (m_Parameters.m_BiasEnabled)
739 {
740 ValidatePointer(m_Bias, "DepthwiseConvolution2dQueueDescriptor", "bias");
741 ValidateTensorNumDimensions(m_Bias->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor", 1, "bias");
742 ValidateBiasTensorQuantization(m_Bias->GetTensorInfo(),
743 workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(), "DepthwiseConvolution2dQueueDescriptor");
744
745 ValidateTensorDataType(m_Bias->GetTensorInfo(),
746 GetBiasDataType(workloadInfo.m_InputTensorInfos[0].GetDataType()),
747 "DepthwiseConvolution2dQueueDescriptor", "bias");
748 }
749
750 ValidateTensorQuantizationMultiplier(workloadInfo.m_InputTensorInfos[0], m_Weight->GetTensorInfo(),
751 workloadInfo.m_OutputTensorInfos[0], "DepthwiseConvolution2dQueueDescriptor", "input", "weights", "output");
Ruomei Yan88d44b82019-05-23 14:29:06 +0100752
753 // Check the supported data types
754 std::vector<DataType> supportedTypes = {
755 DataType::Float32,
756 DataType::QuantisedAsymm8,
757 DataType::QuantisedSymm16,
758 DataType::Float16
759 };
760
761 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
762 supportedTypes,
763 "DepthwiseConvolution2dQueueDescriptor");
764
765 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
766 {workloadInfo.m_InputTensorInfos[0].GetDataType()},
767 "DepthwiseConvolution2dQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000768}
769
770void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
771{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100772 ValidateNumInputs(workloadInfo, "PermuteQueueDescriptor", 1);
773 ValidateNumOutputs(workloadInfo, "PermuteQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000774
775 const PermutationVector& mapping = m_Parameters.m_DimMappings;
776
777 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
778 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
779
780 ValidateTensorNumDimensions(input, "PermuteQueueDescriptor", mapping.GetSize(), "input");
781 ValidateTensorNumDimensions(output, "PermuteQueueDescriptor", mapping.GetSize(), "output");
782
783 for (unsigned int i = 0; i < mapping.GetSize(); ++i)
784 {
785 if (input.GetShape()[i] != output.GetShape()[mapping[i]])
786 {
787 throw InvalidArgumentException("PermuteQueueDescriptor: src dimension " + to_string(i) +
788 " (=" + to_string(input.GetShape()[i]) + ") " +
789 "must match dst dimension " + to_string(mapping[i]) +
790 " (=" + to_string(output.GetShape()[mapping[i]]) + ")");
791 }
792 }
793}
794
795void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
796{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100797 ValidateNumInputs(workloadInfo, "Pooling2dQueueDescriptor", 1);
798 ValidateNumOutputs(workloadInfo, "Pooling2dQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000799
800 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "Pooling2dQueueDescriptor", 4, "input");
801 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "Pooling2dQueueDescriptor", 4, "output");
802}
803
804void ResizeBilinearQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
805{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100806 ValidateNumInputs(workloadInfo, "ResizeBilinearQueueDescriptor", 1);
807 ValidateNumOutputs(workloadInfo, "ResizeBilinearQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000808
809 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "ResizeBilinearQueueDescriptor", 4, "input");
810 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "ResizeBilinearQueueDescriptor", 4, "output");
811
telsoa01c577f2c2018-08-31 09:22:23 +0100812 // Resizes bilinear only changes width and height: batch and channel count must match.
telsoa014fcda012018-03-09 14:13:49 +0000813 {
814 const unsigned int inputBatchSize = workloadInfo.m_InputTensorInfos[0].GetShape()[0];
815 const unsigned int outputBatchSize = workloadInfo.m_OutputTensorInfos[0].GetShape()[0];
816 if (inputBatchSize != outputBatchSize)
817 {
818 throw InvalidArgumentException(
819 boost::str(boost::format("ResizeBilinearQueueDescriptor: Input batch size (%1%) "
820 "does not match output batch size (%2%)") % inputBatchSize % outputBatchSize));
821 }
822 }
823
824 {
Matthew Bentham8800c002018-11-19 13:19:28 +0000825 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
James Conroy59540822018-10-11 12:39:05 +0100826 const unsigned int inputChannelCount =
Matthew Bentham8800c002018-11-19 13:19:28 +0000827 workloadInfo.m_InputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
James Conroy59540822018-10-11 12:39:05 +0100828 const unsigned int outputChannelCount =
Matthew Bentham8800c002018-11-19 13:19:28 +0000829 workloadInfo.m_OutputTensorInfos[0].GetShape()[dimensionIndices.GetChannelsIndex()];
telsoa014fcda012018-03-09 14:13:49 +0000830 if (inputChannelCount != outputChannelCount)
831 {
832 throw InvalidArgumentException(
833 boost::str(boost::format("ResizeBilinearQueueDescriptor: Input channel count (%1%) "
834 "does not match output channel count (%2%)") % inputChannelCount % outputChannelCount));
835 }
836 }
837}
838
839void FakeQuantizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
840{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100841 ValidateNumInputs(workloadInfo, "FakeQuantizationQueueDescriptor", 1);
842 ValidateNumOutputs(workloadInfo, "FakeQuantizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000843
844 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "FakeQuantizationQueueDescriptor", 2, "input");
845 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "FakeQuantizationQueueDescriptor", 2, "output");
846 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
847 workloadInfo.m_OutputTensorInfos[0],
848 "FakeQuantizationQueueDescriptor",
849 "input",
850 "output");
851 if (m_Parameters.m_Min > m_Parameters.m_Max)
852 {
853 throw InvalidArgumentException("FakeQuantizationQueueDescriptor: min cannot be greater than max");
854 }
855
856}
857
858void L2NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
859{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100860 ValidateNumInputs(workloadInfo, "L2NormalizationQueueDescriptor", 1);
861 ValidateNumOutputs(workloadInfo, "L2NormalizationQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000862
863 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "L2NormalizationQueueDescriptor", 4, "input");
864 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "L2NormalizationQueueDescriptor", 4, "output");
865 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
866 workloadInfo.m_OutputTensorInfos[0],
867 "L2NormalizationQueueDescriptor",
868 "input",
869 "output");
870}
871
872void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
873{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100874 ValidateNumInputs(workloadInfo, "ConstantQueueDescriptor", 0);
875 ValidateNumOutputs(workloadInfo, "ConstantQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000876
877 if (!m_LayerOutput)
878 {
879 throw InvalidArgumentException("ConstantQueueDescriptor: No const input specified");
880 }
881
882 ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(),
883 workloadInfo.m_OutputTensorInfos[0],
884 "ConstantQueueDescriptor",
885 "constant",
886 "output");
Nina Drozd58ef2c62019-05-16 12:09:18 +0100887
888 // Check the supported data types
889 std::vector<DataType> supportedTypes =
Nina Drozd2f2778f2019-05-27 10:37:05 +0100890 {
891 DataType::Float32,
892 DataType::Float16,
893 DataType::Signed32,
894 DataType::QuantisedAsymm8,
895 DataType::QuantisedSymm16
896 };
Nina Drozd58ef2c62019-05-16 12:09:18 +0100897
898 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, "ConstantQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000899}
900
901void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
902{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100903 ValidateNumInputs(workloadInfo, "ReshapeQueueDescriptor", 1);
904 ValidateNumOutputs(workloadInfo, "ReshapeQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000905
906 if (workloadInfo.m_InputTensorInfos[0].GetNumElements() != workloadInfo.m_OutputTensorInfos[0].GetNumElements())
907 {
908 throw InvalidArgumentException("ReshapeQueueDescriptor: Input tensor has " +
909 to_string(workloadInfo.m_InputTensorInfos[0].GetNumElements()) + " but output tensor has " +
910 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
911 }
Nina Drozd2f2778f2019-05-27 10:37:05 +0100912
913 // Check the supported data types
914 std::vector<DataType> supportedTypes =
915 {
916 DataType::Float32,
917 DataType::Float16,
Nina Drozd8ed4b8c2019-05-29 10:41:04 +0100918 DataType::QuantisedAsymm8,
919 DataType::QuantisedSymm16
Nina Drozd2f2778f2019-05-27 10:37:05 +0100920 };
921
922 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, "ReshapeQueueDescriptor");
923 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0], supportedTypes, "ReshapeQueueDescriptor");
telsoa014fcda012018-03-09 14:13:49 +0000924}
925
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000926void SpaceToBatchNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
927{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100928 ValidateNumInputs(workloadInfo, "SpaceToBatchNdQueueDescriptor", 1);
929 ValidateNumOutputs(workloadInfo, "SpaceToBatchNdQueueDescriptor", 1);
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000930
931 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "SpaceToBatchNdQueueDescriptor", 4, "input");
932 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "SpaceToBatchNdQueueDescriptor", 4, "output");
933
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000934 if (m_Parameters.m_BlockShape.size() != 2)
935 {
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000936 throw InvalidArgumentException("Block Shape must contain 2 spatial dimensions");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000937 }
938
939 if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size())
940 {
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000941 throw InvalidArgumentException("Pad List must contain the same number of dimensions as Block Shape.");
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000942 }
943
944 const TensorShape inputShape = workloadInfo.m_InputTensorInfos[0].GetShape();
945
946 std::pair<unsigned int, unsigned int> heightPad = m_Parameters.m_PadList[0];
947 std::pair<unsigned int, unsigned int> widthPad = m_Parameters.m_PadList[1];
948
Matthew Bentham8800c002018-11-19 13:19:28 +0000949 DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout);
950 unsigned int inputHeight = inputShape[dimensionIndices.GetHeightIndex()]
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000951 + heightPad.first + heightPad.second;
952
Matthew Bentham8800c002018-11-19 13:19:28 +0000953 unsigned int inputWidth = inputShape[dimensionIndices.GetWidthIndex()]
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000954 + widthPad.first + widthPad.second;
955
956 unsigned int numInputElements = inputShape[0] * inputHeight * inputWidth
Matthew Bentham8800c002018-11-19 13:19:28 +0000957 * inputShape[dimensionIndices.GetChannelsIndex()];
Nattapat Chaimanowong3ea76d52018-11-09 14:10:38 +0000958
959 if (workloadInfo.m_OutputTensorInfos[0].GetNumElements() != numInputElements)
960 {
961 throw InvalidArgumentException("SpaceToBatchNdQueueDescriptor: Input tensor has " +
962 to_string(numInputElements) + " after padding but output tensor has " +
963 to_string(workloadInfo.m_OutputTensorInfos[0].GetNumElements()) + " elements.");
964 }
965
966 if (inputHeight % m_Parameters.m_BlockShape[0] != 0 || inputWidth % m_Parameters.m_BlockShape[1] != 0)
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +0000967 {
968 throw InvalidArgumentException(
969 "Input shape after padding must be divisible by Block Shape in all spatial dimensions");
970 }
971}
972
telsoa014fcda012018-03-09 14:13:49 +0000973void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
974{
Sadik Armaganeff363d2019-04-05 15:25:46 +0100975 ValidateNumInputs(workloadInfo, "FloorQueueDescriptor", 1);
976 ValidateNumOutputs(workloadInfo, "FlootQueueDescriptor", 1);
telsoa014fcda012018-03-09 14:13:49 +0000977
978 if (workloadInfo.m_InputTensorInfos[0] != workloadInfo.m_OutputTensorInfos[0])
979 {
980 throw InvalidArgumentException("FloorQueueDescriptor: Input and output tensor infos do not match.");
981 }
982}
983
telsoa01c577f2c2018-08-31 09:22:23 +0100984void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
985{
986 ValidateTensorNumDimensions(workloadInfo.m_InputTensorInfos[0], "LstmQueueDescriptor", 2, "input");
987 ValidateTensorNumDimensions(workloadInfo.m_OutputTensorInfos[0], "LstmQueueDescriptor", 2, "output");
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +0100988
989 std::vector<DataType> supportedTypes = {
Conor Kennedyb9971c92019-05-07 07:14:23 +0100990 DataType::Float16,
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +0100991 DataType::Float32,
Conor Kennedyb9971c92019-05-07 07:14:23 +0100992 DataType::QuantisedSymm16
Nattapat Chaimanowongeb2b3292019-05-07 12:02:30 +0100993 };
994
995 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
996 supportedTypes,
997 "LstmQueueDescriptor");
998
999 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1000 supportedTypes,
1001 "LstmQueueDescriptor");
telsoa01c577f2c2018-08-31 09:22:23 +01001002}
1003
1004void ConvertFp32ToFp16QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1005{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001006 ValidateNumInputs(workloadInfo, "ConvertFp32ToFp16QueueDescriptor", 1);
1007 ValidateNumOutputs(workloadInfo, "ConvertFp32ToFp16QueueDescriptor", 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001008
1009 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float32)
1010 {
1011 throw InvalidArgumentException("ConvertFp32ToFp16QueueDescriptor: Input tensor type must be Float32.");
1012 }
1013
1014 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float16)
1015 {
1016 throw InvalidArgumentException("ConvertFp32ToFp16QueueDescriptor: Output tensor type must be Float16.");
1017 }
1018
1019 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1020 workloadInfo.m_OutputTensorInfos[0],
1021 "ConvertFp32ToFp16QueueDescriptor",
1022 "input",
1023 "output");
1024}
1025
1026void ConvertFp16ToFp32QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1027{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001028 ValidateNumInputs(workloadInfo, "ConvertFp16ToFp32QueueDescriptor", 1);
1029 ValidateNumOutputs(workloadInfo, "ConvertFp16ToFp32QueueDescriptor", 1);
telsoa01c577f2c2018-08-31 09:22:23 +01001030
1031 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float16)
1032 {
1033 throw InvalidArgumentException("ConvertFp16ToFp32QueueDescriptor: Input tensor type must be Float16.");
1034 }
1035 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float32)
1036 {
1037 throw InvalidArgumentException("ConvertFp16ToFp32QueueDescriptor: Output tensor type must be Float32.");
1038 }
1039
1040 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1041 workloadInfo.m_OutputTensorInfos[0],
1042 "ConvertFp16ToFp32QueueDescriptor",
1043 "input",
1044 "output");
1045}
1046
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001047void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1048{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001049 ValidateNumInputs(workloadInfo, "DivisionQueueDescriptor", 2);
1050 ValidateNumOutputs(workloadInfo, "DivisionQueueDescriptor", 1);
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001051
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001052 std::vector<DataType> supportedTypes = {
1053 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001054 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +01001055 DataType::QuantisedSymm16,
1056 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001057 };
1058
1059 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1060 supportedTypes,
1061 "DivisionQueueDescriptor");
1062
1063 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1064 supportedTypes,
1065 "DivisionQueueDescriptor");
1066
1067 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1068 supportedTypes,
1069 "DivisionQueueDescriptor");
1070
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001071 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1072 workloadInfo.m_InputTensorInfos[1],
1073 workloadInfo.m_OutputTensorInfos[0],
1074 "DivisionQueueDescriptor",
1075 "first input",
1076 "second input");
1077}
1078
David Beckc2044fe2018-09-05 15:00:38 +01001079void SubtractionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1080{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001081 ValidateNumInputs(workloadInfo, "SubtractionQueueDescriptor", 2);
1082 ValidateNumOutputs(workloadInfo, "SubtractionQueueDescriptor", 1);
David Beckc2044fe2018-09-05 15:00:38 +01001083
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001084 std::vector<DataType> supportedTypes = {
1085 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001086 DataType::QuantisedAsymm8,
Jim Flynn82fbe7c2019-04-02 15:19:08 +01001087 DataType::QuantisedSymm16,
1088 DataType::Float16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001089 };
1090
1091 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1092 supportedTypes,
1093 "SubtractionQueueDescriptor");
1094
1095 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1096 supportedTypes,
1097 "SubtractionQueueDescriptor");
1098
1099 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1100 supportedTypes,
1101 "SubtractionQueueDescriptor");
1102
David Beckc2044fe2018-09-05 15:00:38 +01001103 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1104 workloadInfo.m_InputTensorInfos[1],
1105 workloadInfo.m_OutputTensorInfos[0],
1106 "SubtractionQueueDescriptor",
1107 "first input",
1108 "second input");
1109}
1110
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001111void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1112{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001113 ValidateNumInputs(workloadInfo, "MaximumQueueDescriptor", 2);
1114 ValidateNumOutputs(workloadInfo, "MaximumQueueDescriptor", 1);
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001115
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001116 std::vector<DataType> supportedTypes = {
1117 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001118 DataType::QuantisedAsymm8,
1119 DataType::QuantisedSymm16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001120 };
1121
1122 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1123 supportedTypes,
1124 "MaximumQueueDescriptor");
1125
1126 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1127 supportedTypes,
1128 "MaximumQueueDescriptor");
1129
1130 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1131 supportedTypes,
1132 "MaximumQueueDescriptor");
1133
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001134 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1135 workloadInfo.m_InputTensorInfos[1],
1136 workloadInfo.m_OutputTensorInfos[0],
1137 "MaximumQueueDescriptor",
1138 "first input",
1139 "second input");
1140}
1141
narpra01a6bf9122018-09-10 09:50:09 +01001142void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1143{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001144 ValidateNumInputs(workloadInfo, "MeanQueueDescriptor", 1);
1145 ValidateNumOutputs(workloadInfo, "MeanQueueDescriptor", 1);
narpra01eb061912018-09-10 17:35:27 +01001146
1147 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
1148 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1149
narpra0132b90462018-09-13 11:07:48 +01001150 if (m_Parameters.m_KeepDims)
narpra01eb061912018-09-10 17:35:27 +01001151 {
1152 ValidateTensorNumDimensions(output, "MeanQueueDescriptor", input.GetNumDimensions(), "output");
1153 }
narpra0132b90462018-09-13 11:07:48 +01001154 else if (m_Parameters.m_Axis.empty())
narpra01eb061912018-09-10 17:35:27 +01001155 {
1156 ValidateTensorNumDimensions(output, "MeanQueueDescriptor", 1, "output");
1157 }
1158 else
1159 {
narpra0132b90462018-09-13 11:07:48 +01001160 auto outputDim = input.GetNumDimensions() - boost::numeric_cast<unsigned int>(m_Parameters.m_Axis.size());
narpra01eb061912018-09-10 17:35:27 +01001161 ValidateTensorNumDimensions(output,
1162 "MeanQueueDescriptor",
1163 outputDim > 0 ? outputDim : 1,
1164 "output");
1165 }
narpra01a6bf9122018-09-10 09:50:09 +01001166}
1167
jimfly012c9322a2018-09-19 10:59:49 +01001168void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1169{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001170 ValidateNumInputs(workloadInfo, "PadQueueDescriptor", 1);
1171 ValidateNumOutputs(workloadInfo, "PadQueueDescriptor", 1);
jimfly012c9322a2018-09-19 10:59:49 +01001172
1173 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
Nina Drozd661dfa72018-10-02 11:14:17 +01001174 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1175
jimfly012c9322a2018-09-19 10:59:49 +01001176 // input and output should have the same number of dimensions
1177 ValidateTensorNumDimensions(output, "PadQueueDescriptor", input.GetNumDimensions(), "output");
1178 // there should be entry in the pad list for each dimension in the input tensor
1179 if (m_Parameters.m_PadList.size() != input.GetNumDimensions()) {
1180 throw InvalidArgumentException("Pad List should contain the same number of entries as there"
1181 " are dimensions in the input tensor that is " +
1182 to_string(input.GetNumDimensions()) + " entries " +
1183 " not " + to_string(m_Parameters.m_PadList.size()) + " entries.");
1184 }
1185}
1186
Derek Lambertia9cca6a2019-03-25 15:41:58 +00001187void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1188{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001189 ValidateNumInputs(workloadInfo, "QuantizeQueueDescriptor", 1);
1190 ValidateNumOutputs(workloadInfo, "QuantizeQueueDescriptor", 1);
Derek Lambertia9cca6a2019-03-25 15:41:58 +00001191
1192
1193 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::Float32)
1194 {
1195 throw InvalidArgumentException("Quantize only accepts Float32 inputs.");
1196 }
1197
1198 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::QuantisedAsymm8 &&
1199 workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::QuantisedSymm16)
1200 {
1201 throw InvalidArgumentException("Output of quantized layer must be quantized type.");
1202 }
1203}
1204
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +00001205void BatchToSpaceNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1206{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001207 ValidateNumInputs(workloadInfo, "BatchToSpaceNdQueueDescriptor", 1);
1208 ValidateNumOutputs(workloadInfo, "BatchToSpaceNdQueueDescriptor", 1);
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +00001209}
1210
Conor Kennedy430b5d82018-11-14 15:28:28 +00001211void StridedSliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1212{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001213 ValidateNumInputs(workloadInfo, "StridedSliceQueueDescriptor", 1);
1214 ValidateNumOutputs(workloadInfo, "StridedSliceQueueDescriptor", 1);
Conor Kennedy430b5d82018-11-14 15:28:28 +00001215
1216 const TensorInfo& input = workloadInfo.m_InputTensorInfos[0];
1217 const uint32_t rank = input.GetNumDimensions();
1218
Nattapat Chaimanowonga0d28442018-11-21 16:48:17 +00001219 if (rank > 4)
1220 {
1221 throw InvalidArgumentException(
1222 "StridedSliceLayer: Input tensors with rank greater than 4 are not supported");
1223 }
1224
Conor Kennedy430b5d82018-11-14 15:28:28 +00001225 // Begin, End & Stride length must be of rank(input0)
1226 if (m_Parameters.m_Begin.size() != rank)
1227 {
1228 throw InvalidArgumentException("StridedSliceLayer: Begin length must be of rank input0("
1229 + to_string(rank) + ")");
1230 }
1231
1232 if (m_Parameters.m_End.size() != rank)
1233 {
1234 throw InvalidArgumentException("StridedSliceLayer: End length must be of rank input0("
1235 + to_string(rank) + ")");
1236 }
1237
1238 if (m_Parameters.m_Stride.size() != rank)
1239 {
1240 throw InvalidArgumentException("StridedSliceLayer: Stride length must be of rank input0("
1241 + to_string(rank) + ")");
1242 }
1243
1244 // Stride entries must be non-zero
1245 for (auto& stride : m_Parameters.m_Stride)
1246 {
1247 if (stride == 0)
1248 {
1249 throw InvalidArgumentException("StridedSliceLayer: Stride entries must be non-zero");
1250 }
1251 }
1252}
1253
kevmay0190539692018-11-29 08:40:19 +00001254void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1255{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001256 ValidateNumInputs(workloadInfo, "MinimumQueueDescriptor", 2);
1257 ValidateNumOutputs(workloadInfo, "MinimumQueueDescriptor", 1);
kevmay0190539692018-11-29 08:40:19 +00001258
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001259 std::vector<DataType> supportedTypes = {
1260 DataType::Float32,
Sadik Armagan2999a022019-04-09 14:20:12 +01001261 DataType::QuantisedAsymm8,
1262 DataType::QuantisedSymm16
Sadik Armagan2e6dc3a2019-04-03 17:48:18 +01001263 };
1264
1265 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1266 supportedTypes,
1267 "MinimumQueueDescriptor");
1268
1269 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1270 supportedTypes,
1271 "MinimumQueueDescriptor");
1272
1273 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1274 supportedTypes,
1275 "MinimumQueueDescriptor");
1276
kevmay0190539692018-11-29 08:40:19 +00001277 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1278 workloadInfo.m_InputTensorInfos[1],
1279 workloadInfo.m_OutputTensorInfos[0],
1280 "MinimumQueueDescriptor",
1281 "first input",
1282 "second input");
1283}
1284
Nattapat Chaimanowonga9a1cf12018-12-03 16:06:49 +00001285void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1286{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001287 ValidateNumInputs(workloadInfo, "DebugQueueDescriptor", 1);
1288 ValidateNumOutputs(workloadInfo, "DebugQueueDescriptor", 1);
Nattapat Chaimanowonga9a1cf12018-12-03 16:06:49 +00001289}
1290
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001291void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1292{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001293 ValidateNumInputs(workloadInfo, "EqualQueueDescriptor", 2);
1294 ValidateNumOutputs(workloadInfo, "EqualQueueDescriptor", 1);
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001295
1296 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1297 workloadInfo.m_InputTensorInfos[1],
1298 workloadInfo.m_OutputTensorInfos[0],
1299 "EqualQueueDescriptor",
1300 "first input",
1301 "second input");
kevmay012b4d88e2019-01-24 14:05:09 +00001302
1303 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
1304 {
1305 throw InvalidArgumentException("EqualQueueDescriptor: Output tensor type must be Boolean.");
1306 }
FrancisMurtagh30cdfca2018-12-18 12:57:35 +00001307}
1308
FrancisMurtagh878f0232018-12-19 10:56:15 +00001309void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1310{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001311 ValidateNumInputs(workloadInfo, "GreaterQueueDescriptor", 2);
1312 ValidateNumOutputs(workloadInfo, "GreaterQueueDescriptor", 1);
FrancisMurtagh878f0232018-12-19 10:56:15 +00001313
1314 ValidateBroadcastTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1315 workloadInfo.m_InputTensorInfos[1],
1316 workloadInfo.m_OutputTensorInfos[0],
1317 "GreaterQueueDescriptor",
1318 "first input",
1319 "second input");
kevmay012b4d88e2019-01-24 14:05:09 +00001320
1321 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Boolean)
1322 {
1323 throw InvalidArgumentException("GreaterQueueDescriptor: Output tensor type must be Boolean.");
1324 }
FrancisMurtagh878f0232018-12-19 10:56:15 +00001325}
1326
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001327void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1328{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001329 ValidateNumInputs(workloadInfo, "RsqrtQueueDescriptor", 1);
1330 ValidateNumOutputs(workloadInfo, "RsqrtQueueDescriptor", 1);
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001331 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1332 workloadInfo.m_OutputTensorInfos[0],
1333 "RsqrtQueueDescriptor",
1334 "input",
1335 "output");
1336}
1337
narpra01b89b05f2019-01-16 09:53:09 +00001338void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1339{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001340 ValidateNumInputs(workloadInfo, "GatherQueueDescriptor", 2);
1341 ValidateNumOutputs(workloadInfo, "GatherQueueDescriptor", 1);
narpra014951d842019-01-18 16:53:53 +00001342
1343 const TensorInfo& indices = workloadInfo.m_InputTensorInfos[1];
1344
1345 if (indices.GetDataType() != DataType::Signed32)
1346 {
1347 throw InvalidArgumentException("GatherQueueDescriptor: Indices tensor type must be int32.");
1348 }
1349
1350 const TensorInfo& params = workloadInfo.m_InputTensorInfos[0];
1351 const TensorInfo& output = workloadInfo.m_OutputTensorInfos[0];
1352 unsigned int paramsDim = params.GetNumDimensions();
1353 unsigned int indicesDim = indices.GetNumDimensions();
1354 unsigned int outputDim = paramsDim - 1 + indicesDim;
1355
1356 ValidateTensorNumDimensions(output, "GatherQueueDescriptor", outputDim, "output");
narpra01b89b05f2019-01-16 09:53:09 +00001357}
1358
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001359void DetectionPostProcessQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1360{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001361 ValidateNumInputs(workloadInfo, "DetectionPostProcessQueueDescriptor", 2);
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001362
1363 if (workloadInfo.m_OutputTensorInfos.size() != 4)
1364 {
1365 throw InvalidArgumentException("DetectionPostProcessQueueDescriptor: Requires exactly four outputs. " +
1366 to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided.");
1367 }
1368
1369 if (m_Anchors == nullptr)
1370 {
1371 throw InvalidArgumentException("DetectionPostProcessQueueDescriptor: Anchors tensor descriptor is missing.");
1372 }
1373
1374 const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0];
1375 const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1];
1376 const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo();
1377 const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0];
Narumol Prangnawarat6d302bf2019-02-04 11:46:26 +00001378 const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1];
1379 const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2];
Narumol Prangnawaratbc67cef2019-01-31 15:31:54 +00001380 const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3];
1381
1382 ValidateTensorNumDimensions(boxEncodingsInfo, "DetectionPostProcessQueueDescriptor", 3, "box encodings");
1383 ValidateTensorNumDimensions(scoresInfo, "DetectionPostProcessQueueDescriptor", 3, "scores");
1384 ValidateTensorNumDimensions(anchorsInfo, "DetectionPostProcessQueueDescriptor", 2, "anchors");
1385
1386 ValidateTensorNumDimensions(detectionBoxesInfo, "DetectionPostProcessQueueDescriptor", 3, "detection boxes");
1387 ValidateTensorNumDimensions(detectionScoresInfo, "DetectionPostProcessQueueDescriptor", 2, "detection scores");
1388 ValidateTensorNumDimensions(detectionClassesInfo, "DetectionPostProcessQueueDescriptor", 2, "detection classes");
1389 ValidateTensorNumDimensions(numDetectionsInfo, "DetectionPostProcessQueueDescriptor", 1, "num detections");
1390
1391 ValidateTensorDataType(detectionBoxesInfo, DataType::Float32,
1392 "DetectionPostProcessQueueDescriptor", "detection boxes");
1393 ValidateTensorDataType(detectionScoresInfo, DataType::Float32,
1394 "DetectionPostProcessQueueDescriptor", "detection scores");
1395 ValidateTensorDataType(detectionClassesInfo, DataType::Float32,
1396 "DetectionPostProcessQueueDescriptor", "detection classes");
1397 ValidateTensorDataType(numDetectionsInfo, DataType::Float32,
1398 "DetectionPostProcessQueueDescriptor", "num detections");
1399
1400 if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f)
1401 {
1402 throw InvalidArgumentException("DetectionPostProcessQueueDescriptor: Intersection over union threshold "
1403 "must be positive and less than or equal to 1.");
1404 }
1405 if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1)
1406 {
1407 throw InvalidArgumentException("DetectionPostProcessQueueDescriptor: Number of classes with background "
1408 "should be equal to number of classes + 1.");
1409 }
1410}
1411
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00001412void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1413{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001414 ValidateNumInputs(workloadInfo, "DequantizeQueueDescriptor", 1);
1415 ValidateNumOutputs(workloadInfo, "DequantizeQueueDescriptor", 1);
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00001416
1417 if (workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::QuantisedAsymm8 &&
1418 workloadInfo.m_InputTensorInfos[0].GetDataType() != DataType::QuantisedSymm16)
1419 {
1420 throw InvalidArgumentException("Input to dequantize layer must be quantized type.");
1421 }
1422
1423 if (workloadInfo.m_OutputTensorInfos[0].GetDataType() != DataType::Float32)
1424 {
1425 throw InvalidArgumentException("Output of dequantize layer must be Float32 type.");
1426 }
1427}
1428
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001429void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1430{
Sadik Armaganeff363d2019-04-05 15:25:46 +01001431 ValidateNumInputs(workloadInfo, "MergeQueueDescriptor", 2);
1432 ValidateNumOutputs(workloadInfo, "MergeQueueDescriptor", 1);
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001433
1434 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1435 workloadInfo.m_InputTensorInfos[1],
1436 "MergeQueueDescriptor",
1437 "input0",
1438 "input1");
1439
1440 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1441 workloadInfo.m_OutputTensorInfos[0],
1442 "MergeQueueDescriptor",
1443 "input0",
1444 "output");
1445
1446 const DataType dataType = workloadInfo.m_InputTensorInfos[0].GetDataType();
1447 ValidateTensorDataType(workloadInfo.m_InputTensorInfos[1], dataType, "MergeQueueDescriptor", "input1");
1448 ValidateTensorDataType(workloadInfo.m_OutputTensorInfos[0], dataType, "MergeQueueDescriptor", "output");
1449}
1450
Sadik Armaganeff363d2019-04-05 15:25:46 +01001451void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1452{
1453 ValidateNumInputs(workloadInfo, "SwitchQueueDescriptor", 2);
1454 ValidateNumOutputs(workloadInfo, "SwitchQueueDescriptor", 2);
1455
1456 std::vector<DataType> supportedTypes = {
1457 DataType::Float32,
1458 DataType::QuantisedAsymm8,
1459 DataType::QuantisedSymm16
1460 };
1461
1462 ValidateDataTypes(workloadInfo.m_InputTensorInfos[0],
1463 supportedTypes,
1464 "SwitchQueueDescriptor");
1465
1466 ValidateDataTypes(workloadInfo.m_InputTensorInfos[1],
1467 supportedTypes,
1468 "SwitchQueueDescriptor");
1469
1470 ValidateDataTypes(workloadInfo.m_OutputTensorInfos[0],
1471 supportedTypes,
1472 "SwitchQueueDescriptor");
1473
1474 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1475 workloadInfo.m_OutputTensorInfos[0],
1476 "SwitchQueueDescriptor",
1477 "input0",
1478 "output0");
1479
1480 ValidateTensorShapesMatch(workloadInfo.m_InputTensorInfos[0],
1481 workloadInfo.m_OutputTensorInfos[1],
1482 "SwitchQueueDescriptor",
1483 "input0",
1484 "output1");
1485}
1486
Matteo Martincigh49124022019-01-11 13:25:59 +00001487void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
1488{
1489 // This is internally generated so it should not need validation.
1490}
1491
Nattapat Chaimanowonga0d28442018-11-21 16:48:17 +00001492} //namespace armnn