23 struct Sme2ShapeProfile
38 bool IsQuantizedDataType(
DataType dataType)
52 void RecordTensorType(Sme2ShapeProfile& profile,
const TensorInfo& tensorInfo)
54 const DataType dataType = tensorInfo.GetDataType();
56 profile.m_HasQuantized |= IsQuantizedDataType(dataType);
59 bool HasSpecifiedShape(
const TensorInfo& tensorInfo)
61 const TensorShape& shape = tensorInfo.GetShape();
63 shape.AreAllDimensionsSpecified();
66 int64_t NumElements(
const TensorShape& shape)
69 !shape.AreAllDimensionsSpecified())
75 for (
unsigned int i = 0; i < shape.GetNumDimensions(); ++i)
77 elements *=
static_cast<int64_t
>(std::max(shape[i], 1U));
82 int64_t Dimension(
const TensorShape& shape,
unsigned int index)
85 !shape.AreAllDimensionsSpecified() ||
86 index >= shape.GetNumDimensions())
90 return static_cast<int64_t
>(shape[index]);
93 int64_t DimensionFromEnd(
const TensorShape& shape,
unsigned int offset)
95 if (offset == 0 || shape.GetNumDimensions() < offset)
99 return Dimension(shape, shape.GetNumDimensions() - offset);
102 void RecordGemmShape(Sme2ShapeProfile& profile,
108 bool isDenseProjection)
110 if (m <= 0 || n <= 0 || k <= 0)
115 ++profile.m_GemmLikeOps;
117 const bool is1x1 = kernelH == 1 && kernelW == 1;
118 const int64_t macs = m * n * k;
119 profile.m_GemmMacs += macs;
122 profile.m_NonPointwiseGemmMacs += macs;
124 if (isDenseProjection && is1x1 && m <= 256 && n <= 1024 && k <= 1024)
126 ++profile.m_SmallDenseProjectionOps;
129 const bool hasModerateSpatialM = m >= 2048 && m <= 2560;
130 if (is1x1 && hasModerateSpatialM && ((n >= 900 && k <= 384) || (n <= 384 && k >= 900)))
132 profile.m_HasSegmentationShape =
true;
135 if (!is1x1 && ((m >= 25000 && m <= 30000 && n == 64 && k >= 2000) ||
136 (m >= 60000 && m <= 75000 && n == 32 && k >= 500)))
138 profile.m_HasStyleTransferShape =
true;
141 if (!is1x1 && m >= 100000 && n >= 64 && k >= 500)
143 profile.m_HasPoseShape =
true;
146 if (m <= 64 && n >= 4096 && k >= 64 && k <= 1024)
148 profile.m_HasSmallMLargeNProjection =
true;
152 void RecordConvolution2d(Sme2ShapeProfile& profile,
const Layer& layer)
154 if (layer.GetNumInputSlots() < 2 ||
155 layer.GetNumOutputSlots() == 0 ||
156 !layer.GetInputSlot(0).IsTensorInfoSet() ||
157 !layer.GetInputSlot(1).IsTensorInfoSet() ||
158 !layer.GetOutputSlot(0).IsTensorInfoSet())
163 const TensorInfo& inputInfo = layer.GetInputSlot(0).GetTensorInfo();
164 const TensorInfo& filterInfo = layer.GetInputSlot(1).GetTensorInfo();
165 const TensorInfo& outputInfo = layer.GetOutputSlot(0).GetTensorInfo();
166 RecordTensorType(profile, inputInfo);
167 RecordTensorType(profile, filterInfo);
168 RecordTensorType(profile, outputInfo);
170 if (!HasSpecifiedShape(filterInfo) || !HasSpecifiedShape(outputInfo))
175 const Convolution2dDescriptor& descriptor =
176 static_cast<const Convolution2dDescriptor&
>(layer.GetParameters());
177 const TensorShape& filterShape = filterInfo.GetShape();
178 const TensorShape& outputShape = outputInfo.GetShape();
181 if (filterShape.GetNumDimensions() != 4 || outputShape.GetNumDimensions() != 4)
186 const int64_t n = Dimension(filterShape, 0);
187 const int64_t kernelH = Dimension(filterShape, dataLayoutIndex.GetHeightIndex());
188 const int64_t kernelW = Dimension(filterShape, dataLayoutIndex.GetWidthIndex());
189 const int64_t filterElements = NumElements(filterShape);
190 const int64_t inputChannels = n > 0 && kernelH > 0 && kernelW > 0 ?
191 filterElements / (n * kernelH * kernelW) : 0;
192 const int64_t k = kernelH * kernelW * inputChannels;
193 const int64_t outputElements = NumElements(outputShape);
194 const int64_t m = n > 0 ? outputElements / n : 0;
196 RecordGemmShape(profile, m, n, k, kernelH, kernelW,
false);
199 void RecordFullyConnected(Sme2ShapeProfile& profile,
const Layer& layer)
201 if (layer.GetNumInputSlots() < 2 ||
202 layer.GetNumOutputSlots() == 0 ||
203 !layer.GetInputSlot(0).IsTensorInfoSet() ||
204 !layer.GetInputSlot(1).IsTensorInfoSet() ||
205 !layer.GetOutputSlot(0).IsTensorInfoSet())
210 const TensorInfo& inputInfo = layer.GetInputSlot(0).GetTensorInfo();
211 const TensorInfo& weightsInfo = layer.GetInputSlot(1).GetTensorInfo();
212 const TensorInfo& outputInfo = layer.GetOutputSlot(0).GetTensorInfo();
213 RecordTensorType(profile, inputInfo);
214 RecordTensorType(profile, weightsInfo);
215 RecordTensorType(profile, outputInfo);
217 if (!HasSpecifiedShape(inputInfo) || !HasSpecifiedShape(weightsInfo) || !HasSpecifiedShape(outputInfo))
222 const TensorShape& weightsShape = weightsInfo.GetShape();
223 if (weightsShape.GetNumDimensions() < 2)
228 const FullyConnectedDescriptor& descriptor =
229 static_cast<const FullyConnectedDescriptor&
>(layer.GetParameters());
230 const unsigned int nIndex = descriptor.m_TransposeWeightMatrix ? 0U : 1U;
231 const unsigned int kIndex = descriptor.m_TransposeWeightMatrix ? 1U : 0U;
232 const int64_t n = Dimension(weightsShape, nIndex);
233 const int64_t k = Dimension(weightsShape, kIndex);
234 const int64_t outputElements = NumElements(outputInfo.GetShape());
235 const int64_t m = n > 0 ? outputElements / n : 0;
237 RecordGemmShape(profile, m, n, k, 1, 1,
true);
240 void RecordBatchMatMul(Sme2ShapeProfile& profile,
const Layer& layer)
242 if (layer.GetNumInputSlots() < 2 ||
243 layer.GetNumOutputSlots() == 0 ||
244 !layer.GetInputSlot(0).IsTensorInfoSet() ||
245 !layer.GetInputSlot(1).IsTensorInfoSet() ||
246 !layer.GetOutputSlot(0).IsTensorInfoSet())
251 const TensorInfo& lhsInfo = layer.GetInputSlot(0).GetTensorInfo();
252 const TensorInfo& rhsInfo = layer.GetInputSlot(1).GetTensorInfo();
253 const TensorInfo& outputInfo = layer.GetOutputSlot(0).GetTensorInfo();
254 RecordTensorType(profile, lhsInfo);
255 RecordTensorType(profile, rhsInfo);
256 RecordTensorType(profile, outputInfo);
258 if (!HasSpecifiedShape(lhsInfo) || !HasSpecifiedShape(rhsInfo) || !HasSpecifiedShape(outputInfo))
263 const TensorShape& lhsShape = lhsInfo.GetShape();
264 const TensorShape& outputShape = outputInfo.GetShape();
265 const int64_t n = DimensionFromEnd(outputShape, 1);
266 const int64_t m = n > 0 ? NumElements(outputShape) / n : 0;
267 int64_t k = DimensionFromEnd(lhsShape, 1);
270 k = DimensionFromEnd(lhsShape, 2);
273 RecordGemmShape(profile, m, n, k, 1, 1,
true);
276 void RecordDepthwiseConvolution2d(Sme2ShapeProfile& profile,
const Layer& layer)
278 ++profile.m_DepthwiseConvolution2dOps;
280 for (
unsigned int i = 0; i < layer.GetNumInputSlots(); ++i)
282 if (layer.GetInputSlot(i).IsTensorInfoSet())
284 RecordTensorType(profile, layer.GetInputSlot(i).GetTensorInfo());
287 for (
unsigned int i = 0; i < layer.GetNumOutputSlots(); ++i)
289 if (layer.GetOutputSlot(i).IsTensorInfoSet())
291 RecordTensorType(profile, layer.GetOutputSlot(i).GetTensorInfo());
296 Sme2ShapeProfile BuildSme2ShapeProfile(
const Graph& graph,
bool reduceFp32ToFp16)
298 Sme2ShapeProfile profile;
299 profile.m_HasFp16 = reduceFp32ToFp16;
301 for (
const Layer* layer : graph)
303 switch (layer->GetType())
306 RecordConvolution2d(profile, *layer);
309 RecordFullyConnected(profile, *layer);
312 RecordBatchMatMul(profile, *layer);
315 RecordDepthwiseConvolution2d(profile, *layer);
318 for (
unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
320 if (layer->GetInputSlot(i).IsTensorInfoSet())
322 RecordTensorType(profile, layer->GetInputSlot(i).GetTensorInfo());
325 for (
unsigned int i = 0; i < layer->GetNumOutputSlots(); ++i)
327 if (layer->GetOutputSlot(i).IsTensorInfoSet())
329 RecordTensorType(profile, layer->GetOutputSlot(i).GetTensorInfo());
339 unsigned int CapWorkerCount(
unsigned int workers,
unsigned int cap)
341 if (workers == 0 || cap == 0 || cap >= workers)
348 unsigned int GetCpuAccNumberOfThreads(
const ModelOptions& modelOptions)
350 unsigned int numberOfThreads = 0;
351 ParseOptions(modelOptions,
"CpuAcc", [&](std::string name,
const BackendOptions::Var& value)
353 if (name ==
"NumberOfThreads")
355 if (value.IsUnsignedInt())
357 numberOfThreads = value.AsUnsignedInt();
359 else if (value.IsInt() && value.AsInt() > 0)
361 numberOfThreads = static_cast<unsigned int>(value.AsInt());
365 return numberOfThreads;
368 bool HasFloatSmeRegressionRisk(
const Sme2ShapeProfile& profile)
370 const bool isFloatOnly = !profile.m_HasFp16 && !profile.m_HasQuantized;
376 const bool hasHeavySpatialConvolution =
377 profile.m_GemmMacs > 0 &&
378 profile.m_NonPointwiseGemmMacs * 2 >= profile.m_GemmMacs &&
379 !profile.m_HasSegmentationShape;
381 const bool hasSmallDenseGraph =
382 profile.m_DepthwiseConvolution2dOps == 0 &&
383 profile.m_SmallDenseProjectionOps >= 4 &&
384 !profile.m_HasSmallMLargeNProjection;
386 return profile.m_HasPoseShape ||
387 profile.m_HasStyleTransferShape ||
388 hasHeavySpatialConvolution ||
392 bool ShouldDisableSme(
const Sme2ShapeProfile& profile)
394 if (profile.m_GemmLikeOps == 0)
399 if (profile.m_HasFp16)
404 if (profile.m_HasQuantized)
406 return !profile.m_HasSmallMLargeNProjection;
409 return HasFloatSmeRegressionRisk(profile);
412 unsigned int SelectNumberOfThreads(
const Sme2ShapeProfile& profile,
unsigned int requestedThreads)
414 if (!profile.m_HasQuantized || ShouldDisableSme(profile))
416 return requestedThreads;
419 if (profile.m_GemmLikeOps == 0)
421 return CapWorkerCount(requestedThreads, 1);
424 if (profile.m_HasSegmentationShape || profile.m_HasStyleTransferShape)
426 return requestedThreads;
429 if (profile.m_HasPoseShape)
431 return CapWorkerCount(requestedThreads, 4);
434 return CapWorkerCount(requestedThreads, 1);
441 const Sme2ShapeProfile profile = BuildSme2ShapeProfile(graph, reduceFp32ToFp16);
442 if (profile.m_GemmLikeOps == 0)
447 const bool smeEnabled = !ShouldDisableSme(profile);
448 const bool sveEnabled =
true;
449 const unsigned int requestedThreads = GetCpuAccNumberOfThreads(modelOptions);
450 const unsigned int selectedThreads = SelectNumberOfThreads(profile, requestedThreads);
452 modelOptions.push_back(
BackendOptions(
"CpuAcc", {{
"SmeEnabled", smeEnabled}, {
"SveEnabled", sveEnabled}}));
453 if (selectedThreads != requestedThreads)
455 modelOptions.push_back(
BackendOptions(
"CpuAcc", {{
"NumberOfThreads", selectedThreads}}));
unsigned int m_GemmLikeOps
bool m_HasStyleTransferShape
bool m_HasSegmentationShape
int64_t m_NonPointwiseGemmMacs
bool m_HasSmallMLargeNProjection
unsigned int m_DepthwiseConvolution2dOps
unsigned int m_SmallDenseProjectionOps
Provides access to the appropriate indexes for Channels, Height and Width based on DataLayout.
Copyright (c) 2021 ARM Limited and Contributors.
std::vector< BackendOptions > ModelOptions
void ApplySme2ShapePolicy(const Graph &graph, bool reduceFp32ToFp16, ModelOptions &modelOptions)
void ParseOptions(const std::vector< BackendOptions > &options, BackendId backend, F f)
Struct for the users to pass backend specific options.