blob: 38c7f70da5a23ebcaf2ad6b3182e72e15c4c25e2 [file] [log] [blame]
Laurent Carlier749294b2020-06-01 09:03:17 +01001//
Teresa Charlin6bc85252022-12-06 20:43:06 +00002// Copyright © 2017,2022 Arm Ltd and Contributors. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +00005#include <aclCommon/ArmComputeTensorUtils.hpp>
6#include <aclCommon/ArmComputeUtils.hpp>
telsoa014fcda012018-03-09 14:13:49 +00007
Francis Murtagh351d13d2018-09-24 15:01:18 +01008#include "armnn/Exceptions.hpp"
Teresa Charlin6bc85252022-12-06 20:43:06 +00009#include "ArmComputeUtils.hpp"
telsoa014fcda012018-03-09 14:13:49 +000010#include <armnn/Descriptors.hpp>
11
Cathal Corbett4b19d222022-05-11 20:12:17 +010012#include <fmt/format.h>
13
telsoa014fcda012018-03-09 14:13:49 +000014namespace armnn
15{
16namespace armcomputetensorutils
17{
18
Derek Lambertid466a542020-01-22 15:37:29 +000019arm_compute::DataType GetArmComputeDataType(armnn::DataType dataType, bool multiScales)
telsoa014fcda012018-03-09 14:13:49 +000020{
21 switch(dataType)
22 {
Narumol Prangnawarat250d3922020-03-30 16:11:04 +010023 case armnn::DataType::BFloat16:
24 return arm_compute::DataType::BFLOAT16;
Mike Kelly130ec602019-11-08 12:08:35 +000025 case armnn::DataType::Boolean:
26 return arm_compute::DataType::U8;
telsoa01c577f2c2018-08-31 09:22:23 +010027 case armnn::DataType::Float16:
28 return arm_compute::DataType::F16;
telsoa014fcda012018-03-09 14:13:49 +000029 case armnn::DataType::Float32:
telsoa014fcda012018-03-09 14:13:49 +000030 return arm_compute::DataType::F32;
Ryan OShea9add1202020-02-07 10:06:33 +000031 case armnn::DataType::QAsymmS8:
32 return arm_compute::DataType::QASYMM8_SIGNED;
Derek Lambertif90c56d2020-01-10 17:14:08 +000033 case armnn::DataType::QAsymmU8:
telsoa014fcda012018-03-09 14:13:49 +000034 return arm_compute::DataType::QASYMM8;
Derek Lambertif90c56d2020-01-10 17:14:08 +000035 case armnn::DataType::QSymmS16:
Aron Virginas-Tar7a3e2fe2019-06-27 18:54:47 +010036 return arm_compute::DataType::QSYMM16;
Inki Daed4619e22020-09-10 15:33:54 +090037 case armnn::DataType::Signed64:
38 return arm_compute::DataType::S64;
Finn Williamsfd271062019-12-04 14:27:27 +000039 case armnn::DataType::QSymmS8:
Derek Lambertid466a542020-01-22 15:37:29 +000040 {
41 return multiScales ? arm_compute::DataType::QSYMM8_PER_CHANNEL : arm_compute::DataType::QSYMM8;
42 }
telsoa014fcda012018-03-09 14:13:49 +000043 case armnn::DataType::Signed32:
telsoa014fcda012018-03-09 14:13:49 +000044 return arm_compute::DataType::S32;
telsoa014fcda012018-03-09 14:13:49 +000045 default:
Narumol Prangnawaratac2770a2020-04-01 16:51:23 +010046 ARMNN_ASSERT_MSG(false, "Unknown data type");
telsoa014fcda012018-03-09 14:13:49 +000047 return arm_compute::DataType::UNKNOWN;
telsoa014fcda012018-03-09 14:13:49 +000048 }
49}
50
Cathal Corbettfd5bec42022-03-03 15:13:23 +000051armnn::DataType GetArmNNDataType(arm_compute::DataType dataType)
52{
53 switch(dataType)
54 {
55 case arm_compute::DataType::BFLOAT16:
56 return armnn::DataType::BFloat16;
57 case arm_compute::DataType::U8:
58 return armnn::DataType::Boolean;
59 case arm_compute::DataType::F16:
60 return armnn::DataType::Float16;
61 case arm_compute::DataType::F32:
62 return armnn::DataType::Float32;
63 case arm_compute::DataType::QASYMM8_SIGNED:
64 return armnn::DataType::QAsymmS8;
65 case arm_compute::DataType::QASYMM8:
66 return armnn::DataType::QAsymmU8;
67 case arm_compute::DataType::QSYMM16:
68 return armnn::DataType::QSymmS16;
69 case arm_compute::DataType::S64:
70 return armnn::DataType::Signed64;
71 case arm_compute::DataType::QSYMM8_PER_CHANNEL:
72 return armnn::DataType::QSymmS8;
73 case arm_compute::DataType::QSYMM8:
74 return armnn::DataType::QSymmS8;
75 case arm_compute::DataType::S32:
76 return armnn::DataType::Signed32;
77 default:
78 ARMNN_ASSERT_MSG(false, "Unknown data type");
79 return armnn::DataType::Float32;
80 }
81}
82
Matthew Benthamfd899962018-12-31 15:49:42 +000083arm_compute::Coordinates BuildArmComputeReductionCoordinates(size_t inputDimensions,
84 unsigned int originalInputRank,
85 const std::vector<unsigned int>& armnnAxes)
86{
87 arm_compute::Coordinates outAclCoords;
88
89 if (armnnAxes.empty())
90 {
91 // If no reduction axes were provided, then the input must be reduced along all dimensions.
92 // Since Compute Library does not accept an empty vector as the reduction dimensions, we then
93 // manually create a vector including all the input dimensions (in reversed order) as:
94 //
95 // { inputDimensions - 1, inputDimensions - 2, ..., 1, 0 }
96 //
97 outAclCoords.set_num_dimensions(inputDimensions);
98 std::generate(outAclCoords.begin(), outAclCoords.end(), [d = inputDimensions - 1] () mutable { return d--; });
99 }
100 else
101 {
102 // Create a vector of reduction dimensions (in reversed order) with the given reduction axes.
103 //
104 // Adjust the given reduction axes according to the original rank of the input tensor (before ACL applied any
105 // dimension correction).
106 // For example, if the input tensor originally had 4 dimensions, and one of the reduction axes was 2, then the
107 // new value for that reduction axis should be 1.
108 //
109 // Example:
110 // ArmNN input shape = { 1, 1, 3, 2 } -> ACL input shape = { 2, 3 }
111 // ArmNN reduction axis = { 2 } -> ACL reduction axis = { 1 }
112 // ArmNN reduction axis = { 3 } -> ACL reduction axis = { 0 }
113 //
114 // The transformation: ACL reduction axis index = original rank - ArmNN reduction axis index - 1
115 //
116 outAclCoords.set_num_dimensions(armnnAxes.size());
117 std::transform(armnnAxes.begin(), armnnAxes.end(),
118 outAclCoords.begin(),
119 [originalInputRank](unsigned int i){ return originalInputRank - i - 1; });
120 }
121
122 return outAclCoords;
123}
124
telsoa014fcda012018-03-09 14:13:49 +0000125arm_compute::TensorShape BuildArmComputeTensorShape(const armnn::TensorShape& tensorShape)
126{
127 arm_compute::TensorShape shape;
128
telsoa01c577f2c2018-08-31 09:22:23 +0100129 // armnn tensors are (batch, channels, height, width).
130 // arm_compute tensors are (width, height, channels, batch).
telsoa014fcda012018-03-09 14:13:49 +0000131 for (unsigned int i = 0; i < tensorShape.GetNumDimensions(); i++)
132 {
telsoa01c577f2c2018-08-31 09:22:23 +0100133 // Note that our dimensions are stored in the opposite order to ACL's.
Matthew Bentham89105282018-11-20 14:33:33 +0000134 shape.set(tensorShape.GetNumDimensions() - i - 1, tensorShape[i], false);
telsoa014fcda012018-03-09 14:13:49 +0000135
136 // TensorShape::set() flattens leading ones, so that batch size 1 cannot happen.
telsoa01c577f2c2018-08-31 09:22:23 +0100137 // arm_compute tensors expect this.
telsoa014fcda012018-03-09 14:13:49 +0000138 }
139
140 // prevent arm_compute issue where tensor is flattened to nothing
141 if (shape.num_dimensions() == 0)
142 {
143 shape.set_num_dimensions(1);
144 }
145
146 return shape;
147}
148
149// Utility function used to build a TensorInfo object, that can be used to initialise
150// ARM Compute Tensor and CLTensor allocators.
Cathal Corbett4452baf2022-05-13 09:55:59 +0100151// Note: this utility ignores the value of armnn::TensorInfo.IsConstant(). ACL tensors
152// default to constant but Arm NN ones default to non constant. In the cases where
153// we expect ACL to treat a tensor as constant that value must be set after this
154// utility has been called.
telsoa014fcda012018-03-09 14:13:49 +0000155arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo)
156{
Derek Lambertid466a542020-01-22 15:37:29 +0000157 bool multiScales = tensorInfo.HasMultipleQuantizationScales();
telsoa014fcda012018-03-09 14:13:49 +0000158 const arm_compute::TensorShape aclTensorShape = BuildArmComputeTensorShape(tensorInfo.GetShape());
Derek Lambertid466a542020-01-22 15:37:29 +0000159 const arm_compute::DataType aclDataType = GetArmComputeDataType(tensorInfo.GetDataType(), multiScales);
Aron Virginas-Tar13b653f2019-11-01 11:40:39 +0000160
Derek Lambertid466a542020-01-22 15:37:29 +0000161 const arm_compute::QuantizationInfo aclQuantizationInfo = multiScales ?
Aron Virginas-Tar13b653f2019-11-01 11:40:39 +0000162 arm_compute::QuantizationInfo(tensorInfo.GetQuantizationScales()) :
163 arm_compute::QuantizationInfo(tensorInfo.GetQuantizationScale(), tensorInfo.GetQuantizationOffset());
telsoa014fcda012018-03-09 14:13:49 +0000164
165 return arm_compute::TensorInfo(aclTensorShape, 1, aclDataType, aclQuantizationInfo);
166}
167
Francis Murtagh351d13d2018-09-24 15:01:18 +0100168arm_compute::TensorInfo BuildArmComputeTensorInfo(const armnn::TensorInfo& tensorInfo,
169 armnn::DataLayout dataLayout)
170{
Aron Virginas-Tar13b653f2019-11-01 11:40:39 +0000171 arm_compute::TensorInfo aclTensorInfo = BuildArmComputeTensorInfo(tensorInfo);
172 aclTensorInfo.set_data_layout(ConvertDataLayout(dataLayout));
Francis Murtagh351d13d2018-09-24 15:01:18 +0100173
Aron Virginas-Tar13b653f2019-11-01 11:40:39 +0000174 return aclTensorInfo;
Francis Murtagh351d13d2018-09-24 15:01:18 +0100175}
176
Matteo Martincigh747ef822018-12-18 09:26:39 +0000177arm_compute::DataLayout ConvertDataLayout(armnn::DataLayout dataLayout)
178{
179 switch(dataLayout)
180 {
181 case armnn::DataLayout::NHWC : return arm_compute::DataLayout::NHWC;
182
183 case armnn::DataLayout::NCHW : return arm_compute::DataLayout::NCHW;
184
Teresa Charlinec5f7d12021-10-22 17:15:00 +0100185 case armnn::DataLayout::NDHWC : return arm_compute::DataLayout::NDHWC;
186
187 case armnn::DataLayout::NCDHW : return arm_compute::DataLayout::NCDHW;
188
Matteo Martincigh747ef822018-12-18 09:26:39 +0000189 default: throw InvalidArgumentException("Unknown armnn::DataLayout: [" +
190 std::to_string(static_cast<int>(dataLayout)) + "]");
191 }
192}
193
Sadik Armagana3600ba2019-10-10 10:43:20 +0100194arm_compute::PoolingLayerInfo BuildArmComputePoolingLayerInfo(const Pooling2dDescriptor& descriptor,
195 bool fpMixedPrecision)
telsoa014fcda012018-03-09 14:13:49 +0000196{
telsoa01c577f2c2018-08-31 09:22:23 +0100197 // Resolve ARM Compute layer parameters.
Ryan OSheabab8fa92022-03-09 10:29:02 +0000198 const arm_compute::PoolingType poolingType = ConvertPoolingAlgorithmToAclPoolingType(descriptor.m_PoolType);
telsoa01c577f2c2018-08-31 09:22:23 +0100199
Ryan OSheabab8fa92022-03-09 10:29:02 +0000200 const arm_compute::DataLayout dataLayout = ConvertDataLayout(descriptor.m_DataLayout);
Teresa Charlinc809a292020-01-31 10:21:44 +0000201
telsoa01c577f2c2018-08-31 09:22:23 +0100202 bool isGlobalPooling = (descriptor.m_StrideX==0 && descriptor.m_StrideY==0);
203 //use specific constructor if global pooling
204 if(isGlobalPooling)
205 {
Teresa Charlinc809a292020-01-31 10:21:44 +0000206 return arm_compute::PoolingLayerInfo(poolingType, dataLayout);
telsoa01c577f2c2018-08-31 09:22:23 +0100207 }
208
Ryan OSheabab8fa92022-03-09 10:29:02 +0000209 const arm_compute::DimensionRoundingType rounding = ConvertOutputShapeRoundingToAclDimensionRoundingType(
telsoa014fcda012018-03-09 14:13:49 +0000210 descriptor.m_OutputShapeRounding);
Ryan OSheabab8fa92022-03-09 10:29:02 +0000211 const arm_compute::PadStrideInfo padStrideInfo(descriptor.m_StrideX,
telsoa014fcda012018-03-09 14:13:49 +0000212 descriptor.m_StrideY,
213 descriptor.m_PadLeft,
214 descriptor.m_PadRight,
215 descriptor.m_PadTop,
216 descriptor.m_PadBottom,
217 rounding);
218
219 const bool excludePadding = (descriptor.m_PaddingMethod == PaddingMethod::Exclude);
220
Ryan OSheabab8fa92022-03-09 10:29:02 +0000221 const arm_compute::Size2D poolSize(descriptor.m_PoolWidth, descriptor.m_PoolHeight);
surmeh01bceff2f2018-03-29 16:29:27 +0100222
Teresa Charlinc809a292020-01-31 10:21:44 +0000223 return arm_compute::PoolingLayerInfo(poolingType, poolSize, dataLayout, padStrideInfo, excludePadding,
224 fpMixedPrecision);
telsoa014fcda012018-03-09 14:13:49 +0000225}
226
Ryan OSheabab8fa92022-03-09 10:29:02 +0000227arm_compute::Pooling3dLayerInfo BuildArmComputePooling3dLayerInfo(const Pooling3dDescriptor& descriptor,
228 bool fpMixedPrecision)
229{
230 const arm_compute::PoolingType poolingType = ConvertPoolingAlgorithmToAclPoolingType(descriptor.m_PoolType);
231
232 bool isGlobalPooling = (descriptor.m_StrideX==0 && descriptor.m_StrideY==0 && descriptor.m_StrideZ==0);
233 //use specific constructor if global pooling
234 if(isGlobalPooling)
235 {
236 return arm_compute::Pooling3dLayerInfo(poolingType);
237 }
238
239 const arm_compute::Size3D poolSize(descriptor.m_PoolWidth, descriptor.m_PoolHeight, descriptor.m_PoolDepth);
240
241 const arm_compute::Size3D stride(descriptor.m_StrideX,
242 descriptor.m_StrideY,
243 descriptor.m_StrideZ);
244
245 const arm_compute::Padding3D padding(descriptor.m_PadLeft,
246 descriptor.m_PadRight,
247 descriptor.m_PadTop,
248 descriptor.m_PadBottom,
249 descriptor.m_PadFront,
250 descriptor.m_PadBack);
251
252 const bool excludePadding = (descriptor.m_PaddingMethod == PaddingMethod::Exclude);
253
254 const arm_compute::DimensionRoundingType rounding = ConvertOutputShapeRoundingToAclDimensionRoundingType(
255 descriptor.m_OutputShapeRounding);
256
257 return arm_compute::Pooling3dLayerInfo(poolingType,
258 poolSize,
259 stride,
260 padding,
261 excludePadding,
262 fpMixedPrecision,
263 rounding);
264}
265
telsoa014fcda012018-03-09 14:13:49 +0000266arm_compute::NormalizationLayerInfo BuildArmComputeNormalizationLayerInfo(const NormalizationDescriptor& descriptor)
267{
268 const arm_compute::NormType normType =
269 ConvertNormalizationAlgorithmChannelToAclNormType(descriptor.m_NormChannelType);
270 return arm_compute::NormalizationLayerInfo(normType,
271 descriptor.m_NormSize,
272 descriptor.m_Alpha,
273 descriptor.m_Beta,
274 descriptor.m_K,
275 false);
276}
277
278arm_compute::PermutationVector BuildArmComputePermutationVector(const armnn::PermutationVector& perm)
279{
280 arm_compute::PermutationVector aclPerm;
281
282 unsigned int start = 0;
surmeh01bceff2f2018-03-29 16:29:27 +0100283 while ((start < perm.GetSize()) && (start == perm[start]))
telsoa014fcda012018-03-09 14:13:49 +0000284 {
285 ++start;
286 }
287
288 for (unsigned int i = start; i < perm.GetSize(); ++i)
289 {
290 aclPerm.set(i - start, perm[i] - start);
291 }
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000292 return aclPerm;
293}
telsoa014fcda012018-03-09 14:13:49 +0000294
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000295arm_compute::PermutationVector BuildArmComputeTransposeVector(const armnn::PermutationVector& perm)
296{
Teresa Charlin6bc85252022-12-06 20:43:06 +0000297 // As ArmNN indexes are left to right and ACL indexes are right to left,
298 // the permutation vector has to be reversed and then translated into ACL axis.
299 // i.e. {1, 0, 2, 3} --> {3, 2, 0, 1} --> {0, 1, 3, 2}
300
301 // Below an example of how the ArmNN and ACL index format work:
302 // ArmNN Format:
303 // Input Shape {1, 10, 20, 30}
304 // Permutation Vector {1, 0, 2, 3}
305 // Output Shape {10, 1, 20, 30}
306 // dim "1" of input goes into index 0 of the output ([ 10, X, X, X])
307 // dim "0" of input goes into index 1 of the output ([ 10, 1, X, X ])
308 // dim "2" of input goes into index 2 of the output ([ 10, 1, 20, X ])
309 // dim "3" of input goes into index 3 of the output ([ 10, 1, 20, 30 ])
310 // ACL Format:
311 // Input Shape {30, 20, 10, 1}
312 // Permutation Vector {0, 1, 3, 2}
313 // Output Shape {30, 20, 1, 10}
314 // dim "0" of input goes into index 0 of the output ([ 30, X, X, X])
315 // dim "1" of input goes into index 1 of the output ([ 30, 20, X, X ])
316 // dim "3" of input goes into index 2 of the output ([ 30, 20, 1, X ])
317 // dim "2" of input goes into index 3 of the output ([ 30, 20, 1, 10 ])
318
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000319 arm_compute::PermutationVector aclPerm;
Teresa Charlin6bc85252022-12-06 20:43:06 +0000320 auto rank = perm.GetSize();
321
322 // Reverse the order. i.e. {1, 0, 2, 3} --> {3, 2, 0, 1}
323 std::vector<unsigned int> reversedPerm;
324 reversedPerm.reserve(rank);
325 for (unsigned int i = rank; i > 0; --i)
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000326 {
Teresa Charlin6bc85252022-12-06 20:43:06 +0000327 reversedPerm.push_back(perm[i-1]);
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000328 }
329
Teresa Charlin6bc85252022-12-06 20:43:06 +0000330 // Translate from Arm NN axis to ACL axis. i.e. {3, 2, 0, 1} --> {0, 1, 3, 2}
331 for (unsigned int i = 0; i < rank; ++i)
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000332 {
Teresa Charlin6bc85252022-12-06 20:43:06 +0000333 auto aclAxis = rank - 1 - reversedPerm[i];
334 aclPerm.set(i, aclAxis);
Mike Kellyc9ea45a2020-02-28 18:11:58 +0000335 }
telsoa014fcda012018-03-09 14:13:49 +0000336 return aclPerm;
337}
338
Sadik Armaganf4464322018-12-20 16:19:12 +0000339arm_compute::Size2D BuildArmComputeSize2D(const unsigned int width, const unsigned int height)
340{
341 return arm_compute::Size2D(width, height);
342}
343
Kevin May263d7092022-11-29 14:34:48 +0000344arm_compute::PixelValue GetPixelValue(const arm_compute::ITensorInfo* tensorInfo, float value)
Mike Kelly0a08ec62019-07-25 08:39:31 +0100345{
Matthew Sloyan2e5d0b22021-10-21 14:05:31 +0100346 switch (tensorInfo->data_type())
Mike Kelly0a08ec62019-07-25 08:39:31 +0100347 {
Mike Kelly0a08ec62019-07-25 08:39:31 +0100348 case arm_compute::DataType::F16:
Kevin May263d7092022-11-29 14:34:48 +0000349 {
350 arm_compute::PixelValue pixelValue = arm_compute::PixelValue(static_cast<Half>(value));
351 if (isinf(pixelValue.get<Half>())) {
352 throw InvalidArgumentException("Under/Overflow converting float value [" + std::to_string(value) +
353 "] to fp16: [" + std::to_string(pixelValue.get<Half>()) + "]");
354 }
355 return pixelValue;
356 }
Mike Kelly0a08ec62019-07-25 08:39:31 +0100357 case arm_compute::DataType::F32:
Kevin May263d7092022-11-29 14:34:48 +0000358 return arm_compute::PixelValue(value);
Mike Kelly130ec602019-11-08 12:08:35 +0000359 case arm_compute::DataType::QASYMM8:
Kevin May263d7092022-11-29 14:34:48 +0000360 return arm_compute::PixelValue(static_cast<uint8_t>(value));
Mike Kelly130ec602019-11-08 12:08:35 +0000361 case arm_compute::DataType::QSYMM16:
Kevin May263d7092022-11-29 14:34:48 +0000362 return arm_compute::PixelValue(static_cast<int16_t>(value));
Tamas Nyirid3065d72021-11-12 11:22:50 +0000363 case arm_compute::DataType::QSYMM8:
Sadik Armagane5d0b932020-04-09 15:48:44 +0100364 case arm_compute::DataType::QASYMM8_SIGNED:
Mike Kelly130ec602019-11-08 12:08:35 +0000365 case arm_compute::DataType::QSYMM8_PER_CHANNEL:
Kevin May263d7092022-11-29 14:34:48 +0000366 return arm_compute::PixelValue(static_cast<int8_t>(value));
Sadik Armagana792a052020-06-23 16:22:23 +0100367 case arm_compute::DataType::S32:
Kevin May263d7092022-11-29 14:34:48 +0000368 return arm_compute::PixelValue(static_cast<int32_t>(value));
Mike Kelly0a08ec62019-07-25 08:39:31 +0100369 default:
370 throw InvalidArgumentException("Unsupported DataType: [" +
Matthew Sloyan2e5d0b22021-10-21 14:05:31 +0100371 std::to_string(static_cast<int>(tensorInfo->data_type())) + "]");
Mike Kelly0a08ec62019-07-25 08:39:31 +0100372 }
373}
374
Cathal Corbett4b19d222022-05-11 20:12:17 +0100375unsigned int ComputeDepthwiseConv2dDepthMultiplier(armnn::DataLayout layout,
376 const arm_compute::TensorShape& weightsShape,
377 const arm_compute::TensorShape& inputShape)
378{
379 unsigned int depthMultiplier;
380 if (layout == armnn::DataLayout::NHWC)
381 {
382 depthMultiplier = static_cast<uint32_t>(weightsShape[0]) / static_cast<uint32_t>(inputShape[0]);
383 }
384 else if (layout == armnn::DataLayout::NCHW)
385 {
386 depthMultiplier = static_cast<uint32_t>(weightsShape[2]) / static_cast<uint32_t>(inputShape[2]);
387 }
388 else
389 {
390 throw InvalidArgumentException(fmt::format("Unknown data layout for tensor conversion: {}",
391 GetDataLayoutName(layout)));
392 }
393 return depthMultiplier;
394}
395
telsoa014fcda012018-03-09 14:13:49 +0000396} // namespace armcomputetensorutils
397} // namespace armnn