blob: 2fd8142169f756d18245708865225ec144d493f6 [file] [log] [blame]
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +00001//
2// Copyright © 2023 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include <armnn_delegate.hpp>
Ryan OSheaac9607f2023-04-03 11:33:33 +01007#include <OpaqueDelegateUtils.hpp>
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +00008
9#include <Version.hpp>
10
11#include "Activation.hpp"
12#include "ArgMinMax.hpp"
13#include "BatchMatMul.hpp"
14#include "BatchSpace.hpp"
15#include "Comparison.hpp"
16#include "Convolution.hpp"
17#include "Control.hpp"
18#include "ElementwiseBinary.hpp"
19#include "ElementwiseUnary.hpp"
20#include "Fill.hpp"
21#include "FullyConnected.hpp"
22#include "Gather.hpp"
23#include "GatherNd.hpp"
24#include "LogicalBinary.hpp"
25#include "Lstm.hpp"
26#include "Normalization.hpp"
27#include "Pack.hpp"
28#include "Pad.hpp"
29#include "Pooling.hpp"
30#include "Prelu.hpp"
31#include "Quantization.hpp"
32#include "Redefine.hpp"
33#include "Reduce.hpp"
34#include "Resize.hpp"
35#include "Round.hpp"
36#include "Shape.hpp"
37#include "Slice.hpp"
38#include "StridedSlice.hpp"
39#include "Softmax.hpp"
40#include "SpaceDepth.hpp"
41#include "Split.hpp"
42#include "Transpose.hpp"
43#include "UnidirectionalSequenceLstm.hpp"
44#include "Unpack.hpp"
45
46#include <armnn/utility/IgnoreUnused.hpp>
47#include <armnnUtils/Filesystem.hpp>
48#include <armnn/utility/Timer.hpp>
49#include <flatbuffers/flatbuffers.h>
50#include <tensorflow/lite/context_util.h>
51#include <tensorflow/lite/schema/schema_generated.h>
52#include <tensorflow/lite/minimal_logging.h>
53#include <tensorflow/lite/logger.h>
54
55#include <algorithm>
56#include <iostream>
57#include <sstream>
58
59namespace armnnOpaqueDelegate
60{
61
Matthew Sloyan65c21a12023-04-04 12:06:14 +010062const TfLiteStableDelegate TFL_TheStableDelegate =
63{
64 /*delegate_abi_version=*/ TFL_STABLE_DELEGATE_ABI_VERSION,
65 /*delegate_name=*/ "ArmnnDelegatePlugin",
66 /*delegate_version=*/ "1.0.0",
67 /*delegate_plugin=*/ GetArmnnDelegatePluginApi()
68};
69
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +000070ArmnnOpaqueDelegate::ArmnnOpaqueDelegate(armnnDelegate::DelegateOptions options)
71 : m_Options(std::move(options))
72{
73 // Configures logging for ARMNN
74 if (m_Options.IsLoggingEnabled())
75 {
76 armnn::ConfigureLogging(true, true, m_Options.GetLoggingSeverity());
77 }
78 // Create/Get the static ArmNN Runtime. Note that the m_Runtime will be shared by all armnn_delegate
79 // instances so the RuntimeOptions cannot be altered for different armnn_delegate instances.
80 m_Runtime = GetRuntime(m_Options.GetRuntimeOptions());
81 std::vector<armnn::BackendId> backends;
82 if (m_Runtime)
83 {
84 const armnn::BackendIdSet supportedDevices = m_Runtime->GetDeviceSpec().GetSupportedBackends();
85 for (auto& backend : m_Options.GetBackends())
86 {
87 if (std::find(supportedDevices.cbegin(), supportedDevices.cend(), backend) == supportedDevices.cend())
88 {
89 TFLITE_LOG_PROD(tflite::TFLITE_LOG_INFO,
Teresa Charlinf69ae562023-04-27 14:42:23 +010090 "TfLiteArmnnOpaqueDelegate: Requested unknown backend %s", backend.Get().c_str());
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +000091 }
92 else
93 {
94 backends.push_back(backend);
95 }
96 }
97 }
98
99 if (backends.empty())
100 {
101 // No known backend specified
102 throw armnn::InvalidArgumentException("TfLiteArmnnOpaqueDelegate: No known backend specified.");
103 }
104 m_Options.SetBackends(backends);
105
106 TFLITE_LOG_PROD_ONCE(tflite::TFLITE_LOG_INFO, "TfLiteArmnnOpaqueDelegate: Created TfLite ArmNN delegate.");
107}
108
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100109TfLiteStatus DoPrepare(TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueDelegate* tfLiteDelegate, void* data)
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100110{
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100111 // We are required to have the void* data parameter in the function signature, but we don't actually use it.
112 armnn::IgnoreUnused(data);
113
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100114 TfLiteIntArray* supportedOperators =
115 static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100116 (TfLiteOpaqueDelegateGetData(tfLiteDelegate))->IdentifyOperatorsToDelegate(tfLiteContext);
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100117 if(supportedOperators == nullptr)
118 {
119 return kTfLiteError;
120 }
121
122 // ArmNN Opaque Delegate Registration
123 TfLiteRegistrationExternal* kernelRegistration =
124 TfLiteRegistrationExternalCreate(kTfLiteBuiltinDelegate, "TfLiteArmNNOpaqueDelegate", /*version=*/1);
125 if(kernelRegistration == nullptr)
126 {
127 return kTfLiteError;
128 }
129
130 TfLiteRegistrationExternalSetInit(
131 kernelRegistration,
132 [](TfLiteOpaqueContext* tfLiteContext, const char* buffer, size_t length) -> void*
133 {
134 armnn::IgnoreUnused(length);
135 const TfLiteOpaqueDelegateParams* parameters =
136 reinterpret_cast<const TfLiteOpaqueDelegateParams*>(buffer);
137 if(parameters == nullptr)
138 {
139 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
140 "TfLiteArmnnOpaqueDelegate: Unable to get parameters.");
141 return nullptr;
142 }
143
144 return static_cast<void*>(
145 ArmnnSubgraph::Create(tfLiteContext,
146 parameters,
147 static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>(
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100148 parameters->delegate->opaque_delegate_builder->data)));
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100149 }
150 );
151
152 TfLiteRegistrationExternalSetFree(
153 kernelRegistration,
154 [](TfLiteOpaqueContext* tfLiteContext, void* buffer) -> void
155 {
156 armnn::IgnoreUnused(tfLiteContext);
157 if (buffer != nullptr)
158 {
159 delete static_cast<ArmnnSubgraph*>(buffer);
160 }
161 }
162 );
163
164 TfLiteRegistrationExternalSetPrepare(
165 kernelRegistration,
166 [](TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode) -> TfLiteStatus
167 {
168 void* userData = TfLiteOpaqueNodeGetUserData(tfLiteNode);
169 if (userData == nullptr)
170 {
171 return kTfLiteError;
172 }
173 return static_cast<ArmnnSubgraph*>(userData)->Prepare(tfLiteContext);
174 }
175 );
176
177 TfLiteRegistrationExternalSetInvoke(
178 kernelRegistration,
179 [](TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode) -> TfLiteStatus
180 {
181 void* userData = TfLiteOpaqueNodeGetUserData(tfLiteNode);
182 if (userData == nullptr)
183 {
184 return kTfLiteError;
185 }
186
187 return static_cast<ArmnnSubgraph*>(userData)->Invoke(tfLiteContext, tfLiteNode);
188 }
189 );
190
191 const TfLiteStatus status =
192 TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels(
193 tfLiteContext, kernelRegistration, supportedOperators, tfLiteDelegate);
194
195 TfLiteIntArrayFree(supportedOperators);
196 return status;
197}
198
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +0000199TfLiteOpaqueDelegate* TfLiteArmnnOpaqueDelegateCreate(const void* settings)
200{
201 // This method will always create Opaque Delegate with default settings until
202 // we have a DelegateOptions Constructor which can parse the void* settings
203 armnn::IgnoreUnused(settings);
204 auto options = TfLiteArmnnDelegateOptionsDefault();
205 auto* armnnDelegate = new ::armnnOpaqueDelegate::ArmnnOpaqueDelegate(options);
206 return TfLiteOpaqueDelegateCreate(armnnDelegate->GetDelegateBuilder());
207}
208
209::armnnDelegate::DelegateOptions TfLiteArmnnDelegateOptionsDefault()
210{
211 ::armnnDelegate::DelegateOptions options(armnn::Compute::CpuRef);
212 return options;
213}
214
215void TfLiteArmnnOpaqueDelegateDelete(TfLiteOpaqueDelegate* tfLiteDelegate)
216{
217 if (tfLiteDelegate != nullptr)
218 {
219 delete static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>(TfLiteOpaqueDelegateGetData(tfLiteDelegate));
220 TfLiteOpaqueDelegateDelete(tfLiteDelegate);
221 }
222}
223
224const TfLiteOpaqueDelegatePlugin* GetArmnnDelegatePluginApi()
225{
226 static constexpr TfLiteOpaqueDelegatePlugin armnnPlugin{
227 TfLiteArmnnOpaqueDelegateCreate, TfLiteArmnnOpaqueDelegateDelete, TfLiteArmnnOpaqueDelegateErrno};
228 return &armnnPlugin;
229}
230
231const std::string ArmnnOpaqueDelegate::GetVersion() {
232 return OPAQUE_DELEGATE_VERSION;
233}
234
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100235TfLiteIntArray* ArmnnOpaqueDelegate::IdentifyOperatorsToDelegate(TfLiteOpaqueContext* tfLiteContext)
236{
237 TfLiteIntArray* executionPlan = nullptr;
238 if (TfLiteOpaqueContextGetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
239 {
240 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext, "TfLiteArmnnOpaqueDelegate: Unable to get graph execution plan.");
241 return nullptr;
242 }
243
244 // Delegate data with null network
245 DelegateData delegateData(m_Options.GetBackends());
246
247 TfLiteIntArray* nodesToDelegate = TfLiteIntArrayCreate(executionPlan->size);
248 if (nodesToDelegate == nullptr)
249 {
250 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
251 "TfLiteArmnnOpaqueDelegate: Unable to create int array from execution plan.");
252 return nullptr;
253 }
254 nodesToDelegate->size = 0;
255
256 std::set<int32_t> unsupportedOperators;
257
258 for (int i = 0; i < executionPlan->size; ++i)
259 {
260 const int nodeIndex = executionPlan->data[i];
261
262 // If TfLiteOpaqueNodes can be delegated to ArmNN
263 TfLiteOpaqueNode* tfLiteNode = nullptr;
264 TfLiteRegistrationExternal* tfLiteRegistration = nullptr;
265
266 if (TfLiteOpaqueContextGetNodeAndRegistration(
267 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
268 {
269 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
270 "TfLiteArmnnOpaqueDelegate: Unable to get node and registration for node %d.",
271 nodeIndex);
272 continue;
273 }
274
275 TfLiteStatus visitStatus;
276 try
277 {
278 visitStatus = ArmnnSubgraph::VisitNode(
279 delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex);
280 }
281 catch(std::exception& ex)
282 {
283 ARMNN_LOG(error) << "ArmNN Failed to visit node with error: " << ex.what();
284 visitStatus = kTfLiteError;
285 }
286
287 if (visitStatus != kTfLiteOk)
288 {
289 // node is not supported by ArmNN
290 unsupportedOperators.insert(TfLiteRegistrationExternalGetBuiltInCode(tfLiteRegistration));
291 continue;
292 }
293
294 nodesToDelegate->data[nodesToDelegate->size++] = nodeIndex;
295 }
296
297 for (std::set<int32_t>::iterator it=unsupportedOperators.begin(); it!=unsupportedOperators.end(); ++it)
298 {
299 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
300 "Operator %s [%d] is not supported by armnn_opaque_delegate.",
301 tflite::EnumNameBuiltinOperator(tflite::BuiltinOperator(*it)),
302 *it);
303 }
304
305 if (!unsupportedOperators.empty() && m_Options.TfLiteRuntimeFallbackDisabled())
306 {
307 std::stringstream exMessage;
308 exMessage << "TfLiteArmnnOpaqueDelegate: There are unsupported operators in the model. ";
309 exMessage << "Not falling back to TfLite Runtime as fallback is disabled. ";
310 exMessage << "This should only be disabled under test conditions.";
311 throw armnn::Exception(exMessage.str());
312 }
313 if (nodesToDelegate->size == 0)
314 {
315 ARMNN_LOG(info) << "No operators in this model are supported by the Arm NN TfLite delegate." <<
316 " The model will be executed entirely by TfLite runtime.";
317 }
318
319 std::sort(&nodesToDelegate->data[0], &nodesToDelegate->data[nodesToDelegate->size]);
320 return nodesToDelegate;
321}
322
Ryan OSheaac9607f2023-04-03 11:33:33 +0100323TfLiteStatus ArmnnSubgraph::AddInputLayer(DelegateData& delegateData,
324 TfLiteOpaqueContext* tfLiteContext,
325 const TfLiteIntArray* inputs,
326 std::vector<armnn::BindingPointInfo>& inputBindings)
327{
328 const size_t numInputs = static_cast<size_t>(inputs->size);
329 for (unsigned int i = 0; i < numInputs; ++i)
330 {
331 const int32_t tensorId = inputs->data[i];
332 const TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, tensorId);
333
334 if(!tensor)
335 {
336 return kTfLiteError;
337 }
338
339 // Do not create bindings for constant inputs
340 if (TfLiteOpaqueTensorGetAllocationType(tensor) == kTfLiteMmapRo)
341 {
342 continue;
343 }
344
345 auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
346 armnn::IConnectableLayer* layer = delegateData.m_Network->AddInputLayer(bindingId);
347
348 auto tensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tensor);
349 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
350 outputSlot.SetTensorInfo(tensorInfo);
351
352 // Store for creating connections
353 delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] = &outputSlot;
354
355 inputBindings.push_back(std::make_pair(bindingId, tensorInfo));
356 }
357
358 return kTfLiteOk;
359}
360
361TfLiteStatus ArmnnSubgraph::AddOutputLayer(DelegateData& delegateData,
362 TfLiteOpaqueContext* tfLiteContext,
363 const TfLiteIntArray* outputs,
364 std::vector<armnn::BindingPointInfo>& outputBindings)
365{
366 const size_t numOutputs = static_cast<size_t>(outputs->size);
367 for (unsigned int i = 0; i < numOutputs; ++i)
368 {
369 const int32_t tensorId = outputs->data[i];
370 const TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, tensorId);
371
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100372 if(!IsValid(tensor))
Ryan OSheaac9607f2023-04-03 11:33:33 +0100373 {
374 return kTfLiteError;
375 }
376
377 auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
378 armnn::IConnectableLayer* layer = delegateData.m_Network->AddOutputLayer(bindingId);
379
380 auto tensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tensor);
381 ARMNN_ASSERT(delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] != nullptr);
382 delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)]->Connect(layer->GetInputSlot(0));
383 outputBindings.push_back(std::make_pair(bindingId, tensorInfo));
384 }
385
386 return kTfLiteOk;
387}
388
389ArmnnSubgraph* ArmnnSubgraph::Create(TfLiteOpaqueContext* tfLiteContext,
390 const TfLiteOpaqueDelegateParams* parameters,
391 const ArmnnOpaqueDelegate* delegate)
392{
393 const auto startTime = armnn::GetTimeNow();
394 ARMNN_LOG(info) << "ArmnnSubgraph creation";
395
396 TfLiteIntArray* executionPlan;
397 if (TfLiteOpaqueContextGetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
398 {
399 return nullptr;
400 }
401
402 // Initialize DelegateData holds network and output slots information
403 DelegateData delegateData(delegate->m_Options.GetBackends());
404
405 // Build ArmNN Network
John Mcloughlinc5ee0d72023-03-24 12:07:25 +0000406 armnn::NetworkOptions networkOptions = delegate->m_Options.GetOptimizerOptions().GetModelOptions();
Ryan OSheaac9607f2023-04-03 11:33:33 +0100407 armnn::NetworkId networkId;
408 delegateData.m_Network = armnn::INetwork::Create(networkOptions);
409
410 delegateData.m_OutputSlotForNode = std::vector<armnn::IOutputSlot*>(
411 TfLiteOpaqueContextGetNumTensors(tfLiteContext), nullptr);
412
413 std::vector<armnn::BindingPointInfo> inputBindings;
414 std::vector<armnn::BindingPointInfo> outputBindings;
415
416 // Add input layer
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100417 if (AddInputLayer(delegateData, tfLiteContext, parameters->input_tensors, inputBindings) != kTfLiteOk)
Ryan OSheaac9607f2023-04-03 11:33:33 +0100418 {
419 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to add Inputs to the network!");
420 }
421
422 // Parse TfLite delegate nodes to ArmNN
423 const auto parseStartTime = armnn::GetTimeNow();
424 for (int i = 0; i < parameters->nodes_to_replace->size; ++i)
425 {
426 const int nodeIndex = parameters->nodes_to_replace->data[i];
427
428 TfLiteOpaqueNode* tfLiteNode = nullptr;
429 TfLiteRegistrationExternal* tfLiteRegistration = nullptr;
430 if (TfLiteOpaqueContextGetNodeAndRegistration(
431 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
432 {
433 throw armnn::Exception(&"TfLiteArmnnOpaqueDelegate: Unable to get node registration: " [ nodeIndex]);
434 }
435
436 if (VisitNode(delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex) != kTfLiteOk)
437 {
438 throw armnn::Exception(&"TfLiteArmnnOpaqueDelegate: Unable to parse node: " [ nodeIndex]);
439 }
440 }
441 ARMNN_LOG(info) << "Parse nodes to ArmNN time: " << std::setprecision(2)
442 << std::fixed << armnn::GetTimeDuration(parseStartTime).count() << " ms";
443
444 // Add Output layer
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100445 if (AddOutputLayer(delegateData, tfLiteContext, parameters->output_tensors, outputBindings) != kTfLiteOk)
Ryan OSheaac9607f2023-04-03 11:33:33 +0100446 {
447 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to add Outputs to the network!");
448 }
449
450 // Optimize ArmNN network
451 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
452 try
453 {
454 const auto optimizeStartTime = armnn::GetTimeNow();
455 optNet = armnn::Optimize(*(delegateData.m_Network.get()),
456 delegate->m_Options.GetBackends(),
457 delegate->m_Runtime->GetDeviceSpec(),
458 delegate->m_Options.GetOptimizerOptions());
459 ARMNN_LOG(info) << "Optimize ArmnnSubgraph time: " << std::setprecision(2)
460 << std::fixed << armnn::GetTimeDuration(optimizeStartTime).count() << " ms";
461 }
462 catch (std::exception& ex)
463 {
464 std::stringstream exMessage;
465 exMessage << "TfLiteArmnnOpaqueDelegate: Exception (" << ex.what() << ") caught from optimize.";
466 throw armnn::Exception(exMessage.str());
467 }
468 if (!optNet)
469 {
470 // Optimize failed
471 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to optimize the network!");
472 }
473
474 // If set, we will serialize the optimized model into a dot file.
475 const std::string serializeToDotFile = delegate->m_Options.GetSerializeToDot();
476 if (!serializeToDotFile.empty())
477 {
478 ARMNN_LOG(info) << "Writing graph to dot file: " << serializeToDotFile;
479 fs::path filename = serializeToDotFile;
480 std::fstream file(filename.c_str(), std::ios_base::out);
481 optNet->SerializeToDot(file);
482 }
483
484 try
485 {
486 const auto loadStartTime = armnn::GetTimeNow();
487
488 // Load graph into runtime
489 std::string errorMessage;
490 armnn::Status loadingStatus;
491 armnn::MemorySource inputSource = armnn::MemorySource::Undefined;
492 armnn::MemorySource outputSource = armnn::MemorySource::Undefined;
493 // There's a bit of an assumption here that the delegate will only support Malloc memory source.
John Mcloughlinc5ee0d72023-03-24 12:07:25 +0000494 if (delegate->m_Options.GetOptimizerOptions().GetImportEnabled())
Ryan OSheaac9607f2023-04-03 11:33:33 +0100495 {
496 inputSource = armnn::MemorySource::Malloc;
497 }
John Mcloughlinc5ee0d72023-03-24 12:07:25 +0000498 if (delegate->m_Options.GetOptimizerOptions().GetExportEnabled())
Ryan OSheaac9607f2023-04-03 11:33:33 +0100499 {
500 outputSource = armnn::MemorySource::Malloc;
501 }
502 armnn::INetworkProperties networkProperties(false,
503 inputSource,
504 outputSource,
505 delegate->m_Options.GetInternalProfilingState(),
506 delegate->m_Options.GetInternalProfilingDetail());
507 loadingStatus = delegate->m_Runtime->LoadNetwork(networkId,
508 std::move(optNet),
509 errorMessage,
510 networkProperties);
511 if (loadingStatus != armnn::Status::Success)
512 {
513 // Network load failed.
514 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Network could not be loaded: " + errorMessage);
515 }
516
517 ARMNN_LOG(info) << "Load ArmnnSubgraph time: " << std::setprecision(2)
518 << std::fixed << armnn::GetTimeDuration(loadStartTime).count() << " ms";
519 }
520 catch (std::exception& ex)
521 {
522 std::stringstream exMessage;
523 exMessage << "TfLiteArmnnOpaqueDelegate: Exception (" << ex.what() << ") caught from LoadNetwork.";
524 throw armnn::Exception(exMessage.str());
525 }
526
527 // Register debug callback function
528 if (delegate->m_Options.GetDebugCallbackFunction().has_value())
529 {
530 delegate->m_Runtime->RegisterDebugCallback(networkId, delegate->m_Options.GetDebugCallbackFunction().value());
531 }
532
533 ARMNN_LOG(info) << "Overall ArmnnSubgraph creation time: " << std::setprecision(2)
534 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms\n";
535
536 // Create a new SubGraph with networkId and runtime
537 return new ArmnnSubgraph(networkId, delegate->m_Runtime, inputBindings, outputBindings);
538}
539
540TfLiteStatus ArmnnSubgraph::Prepare(TfLiteOpaqueContext* tfLiteContext)
541{
542 armnn::IgnoreUnused(tfLiteContext);
543 return kTfLiteOk;
544}
545
546TfLiteStatus ArmnnSubgraph::Invoke(TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode)
547{
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100548 // Get array of input indices, inputIndexArray is set from the TfLiteOpaqueNodeInputs function
549 // This function turns inputIndexArray into an int array of indices. These indices point to the tensors for
550 // each input slot in the node.
551 const int* inputIndexArray;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100552 int numInputs;
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100553 if(TfLiteOpaqueNodeInputs(tfLiteNode, &inputIndexArray, &numInputs) != kTfLiteOk)
Ryan OSheaac9607f2023-04-03 11:33:33 +0100554 {
555 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to load subgraph inputs!");
556 }
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100557 // Prepare inputs
558 armnn::InputTensors inputTensors;
559 size_t inputIndex = 0;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100560 for (int inputIdx = 0; inputIdx < numInputs; inputIdx++)
561 {
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100562 TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, inputIndexArray[inputIdx]);
Ryan OSheaac9607f2023-04-03 11:33:33 +0100563
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100564 if(!IsValid(tensor))
Ryan OSheaac9607f2023-04-03 11:33:33 +0100565 {
566 return kTfLiteError;
567 }
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100568 // If tensor is not read only
Ryan OSheaac9607f2023-04-03 11:33:33 +0100569 if (TfLiteOpaqueTensorGetAllocationType(tensor) != kTfLiteMmapRo)
570 {
571 const armnn::BindingPointInfo& inputBinding = m_InputBindings[inputIndex];
572 armnn::TensorInfo inputTensorInfo = inputBinding.second;
573 inputTensorInfo.SetConstant(true);
574 const armnn::ConstTensor inputTensor(inputTensorInfo, TfLiteOpaqueTensorData(tensor));
575 inputTensors.emplace_back(inputIdx, inputTensor);
576
577 ++inputIndex;
578 }
579 }
580
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100581 // Get array of output indices, outputIndexArray is set from the TfLiteOpaqueNodeOutputs function
582 // This function turns outputIndexArray into an int array of indices. These indices point to the tensors for
583 // each output slot in the node.
584 const int* outputIndexArray;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100585 int numOutputs;
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100586 if(TfLiteOpaqueNodeOutputs(tfLiteNode, &outputIndexArray, &numOutputs) != kTfLiteOk)
Ryan OSheaac9607f2023-04-03 11:33:33 +0100587 {
588 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to load subgraph outputs!");
589 }
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100590 // Assign the tensors from the outputIndexArray to the armnn BindingPointInfo
591 armnn::OutputTensors outputTensors;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100592 for (int outputIdx = 0; outputIdx < numOutputs; outputIdx++)
593 {
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100594 const armnn::BindingPointInfo& outputBinding = m_OutputBindings[outputIdx];
595 TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, outputIndexArray[outputIdx]);
596 if(!IsValid(tensor))
Ryan OSheaac9607f2023-04-03 11:33:33 +0100597 {
598 return kTfLiteError;
599 }
600
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100601 const armnn::Tensor outputTensor(outputBinding.second, reinterpret_cast<TfLiteTensor*>(tensor)->data
602 .data);
603 outputTensors.emplace_back(outputIndexArray[outputIdx], outputTensor);
Ryan OSheaac9607f2023-04-03 11:33:33 +0100604 }
605
606 // Run graph
607 auto status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
608 // The delegate holds its own Arm NN runtime so this is our last chance to print internal profiling data.
609 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
610 if (profiler && profiler->IsProfilingEnabled())
611 {
612 profiler->Print(std::cout);
613 }
614 return (status == armnn::Status::Success) ? kTfLiteOk : kTfLiteError;
615}
616
617TfLiteStatus ArmnnSubgraph::VisitNode(DelegateData& delegateData,
618 TfLiteOpaqueContext* tfLiteContext,
619 TfLiteRegistrationExternal* tfLiteRegistration,
620 TfLiteOpaqueNode* tfLiteNode,
621 int nodeIndex)
622{
623 switch (TfLiteRegistrationExternalGetBuiltInCode(tfLiteRegistration))
624 {
Teresa Charlinf69ae562023-04-27 14:42:23 +0100625 case kTfLiteBuiltinAbs:
626 return VisitElementwiseUnaryOperator(delegateData,
627 tfLiteContext,
628 tfLiteNode,
629 nodeIndex,
630 kTfLiteBuiltinAbs,
631 armnn::UnaryOperation::Abs);
David Monahan6c53f9f2023-04-27 15:21:19 +0100632 case kTfLiteBuiltinAdd:
633 return VisitElementwiseBinaryOperator(delegateData,
634 tfLiteContext,
635 tfLiteNode,
636 nodeIndex,
637 kTfLiteBuiltinAdd);
John Mcloughlin559d9092023-04-26 20:14:47 +0100638 case kTfLiteBuiltinArgMax:
639 return VisitArgMinMaxOperator(delegateData,
640 tfLiteContext,
641 tfLiteNode,
642 nodeIndex,
643 kTfLiteBuiltinArgMax);
644 case kTfLiteBuiltinArgMin:
645 return VisitArgMinMaxOperator(delegateData,
646 tfLiteContext,
647 tfLiteNode,
648 nodeIndex,
649 kTfLiteBuiltinArgMin);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100650 case kTfLiteBuiltinAveragePool2d:
651 return VisitPooling2dOperator(delegateData,
652 tfLiteContext,
653 tfLiteNode,
654 nodeIndex,
655 kTfLiteBuiltinAveragePool2d);
John Mcloughlin0422cf22023-04-27 16:55:00 +0100656 case kTfLiteBuiltinBatchMatmul:
657 return VisitBatchMatMulOperator(delegateData,
658 tfLiteContext,
659 tfLiteNode,
660 nodeIndex,
661 kTfLiteBuiltinBatchMatmul);
Kevin May81b66f32023-04-26 14:55:36 +0100662 case kTfLiteBuiltinBatchToSpaceNd:
663 return VisitBatchToSpaceNdOperator(delegateData,
664 tfLiteContext,
665 tfLiteNode,
666 nodeIndex,
667 kTfLiteBuiltinBatchToSpaceNd);
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100668 case kTfLiteBuiltinCast:
669 return VisitCastOperator(delegateData,
670 tfLiteContext,
671 tfLiteNode,
672 nodeIndex,
673 kTfLiteBuiltinCast);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100674 case kTfLiteBuiltinCeil:
675 return VisitElementwiseUnaryOperator(delegateData,
676 tfLiteContext,
677 tfLiteNode,
678 nodeIndex,
679 kTfLiteBuiltinCeil,
680 armnn::UnaryOperation::Ceil);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100681 case kTfLiteBuiltinConcatenation:
682 return VisitControlOperator(delegateData,
683 tfLiteContext,
684 tfLiteNode,
685 nodeIndex,
686 kTfLiteBuiltinConcatenation);
Matthew Sloyan080ffd82023-04-24 12:53:04 +0100687 case kTfLiteBuiltinConv2d:
688 return VisitConvolutionOperator(delegateData,
689 tfLiteContext,
690 tfLiteNode,
691 nodeIndex,
692 kTfLiteBuiltinConv2d);
Francis Murtagh3a9e7ba2023-04-26 15:58:39 +0100693 case kTfLiteBuiltinConv3d:
694 return VisitConvolutionOperator(delegateData,
695 tfLiteContext,
696 tfLiteNode,
697 nodeIndex,
698 kTfLiteBuiltinConv3d);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100699 case kTfLiteBuiltinCustom:
700 {
701 // Custom operators are defined by the name rather than the builtin code.
702 // Parse the custom_name param in the registration to point to the correct visitor function.
703 std::string customOperatorName = TfLiteRegistrationExternalGetCustomName(tfLiteRegistration);
704 if ( customOperatorName == "AveragePool3D" )
705 {
706 return VisitPooling3dOperator(delegateData,
707 tfLiteContext,
708 tfLiteNode,
709 nodeIndex,
710 customOperatorName);
711 }
712 else if (customOperatorName == "MaxPool3D")
713 {
714 return VisitPooling3dOperator(delegateData,
715 tfLiteContext,
716 tfLiteNode,
717 nodeIndex,
718 customOperatorName);
719 }
720 // Invalid or unsupported custom operator
721 return kTfLiteError;
722 }
Matthew Sloyan080ffd82023-04-24 12:53:04 +0100723 case kTfLiteBuiltinDepthwiseConv2d:
724 return VisitConvolutionOperator(delegateData,
725 tfLiteContext,
726 tfLiteNode,
727 nodeIndex,
728 kTfLiteBuiltinDepthwiseConv2d);
Francis Murtagh36d94ef2023-04-28 14:05:43 +0100729 case kTfLiteBuiltinDequantize:
730 return VisitDequantizeOperator(delegateData,
731 tfLiteContext,
732 tfLiteNode,
733 nodeIndex,
734 kTfLiteBuiltinDequantize);
David Monahan6c53f9f2023-04-27 15:21:19 +0100735 case kTfLiteBuiltinDiv:
736 return VisitElementwiseBinaryOperator(delegateData,
737 tfLiteContext,
738 tfLiteNode,
739 nodeIndex,
740 kTfLiteBuiltinDiv);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100741 case kTfLiteBuiltinEqual:
742 return VisitComparisonOperator(delegateData,
743 tfLiteContext,
744 tfLiteNode,
745 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100746 kTfLiteBuiltinEqual,
747 armnn::ComparisonOperation::Equal);
Teresa Charlin42362962023-04-28 14:23:33 +0100748 case kTfLiteBuiltinDepthToSpace:
749 return VisitDepthToSpaceOperator(delegateData,
750 tfLiteContext,
751 tfLiteNode,
752 nodeIndex,
753 kTfLiteBuiltinDepthToSpace);
754 case kTfLiteBuiltinElu:
755 return VisitActivationOperator(delegateData,
756 tfLiteContext,
757 tfLiteNode,
758 nodeIndex,
759 kTfLiteBuiltinElu);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100760 case kTfLiteBuiltinExp:
761 return VisitElementwiseUnaryOperator(delegateData,
762 tfLiteContext,
763 tfLiteNode,
764 nodeIndex,
765 kTfLiteBuiltinExp,
766 armnn::UnaryOperation::Exp);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100767 case kTfLiteBuiltinFloor:
768 return VisitFloorOperator(delegateData,
769 tfLiteContext,
770 tfLiteNode,
771 nodeIndex,
772 kTfLiteBuiltinFloor);
David Monahan6c53f9f2023-04-27 15:21:19 +0100773 case kTfLiteBuiltinFloorDiv:
774 return VisitElementwiseBinaryOperator(delegateData,
775 tfLiteContext,
776 tfLiteNode,
777 nodeIndex,
778 kTfLiteBuiltinFloorDiv);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100779 case kTfLiteBuiltinFullyConnected:
780 return VisitFullyConnectedOperator(delegateData,
781 tfLiteContext,
782 tfLiteNode,
783 nodeIndex,
784 kTfLiteBuiltinFullyConnected);
Kevin Mayb2831c52023-04-26 17:27:24 +0100785 case kTfLiteBuiltinGather:
786 return VisitGatherOperator(delegateData,
787 tfLiteContext,
788 tfLiteNode,
789 nodeIndex,
790 kTfLiteBuiltinGather);
791 case kTfLiteBuiltinGatherNd:
792 return VisitGatherNdOperator(delegateData,
793 tfLiteContext,
794 tfLiteNode,
795 nodeIndex,
796 kTfLiteBuiltinGatherNd);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100797 case kTfLiteBuiltinGreater:
798 return VisitComparisonOperator(delegateData,
799 tfLiteContext,
800 tfLiteNode,
801 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100802 kTfLiteBuiltinGreater,
803 armnn::ComparisonOperation::Greater);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100804 case kTfLiteBuiltinGreaterEqual:
805 return VisitComparisonOperator(delegateData,
806 tfLiteContext,
807 tfLiteNode,
808 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100809 kTfLiteBuiltinGreaterEqual,
810 armnn::ComparisonOperation::GreaterOrEqual);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100811 case kTfLiteBuiltinHardSwish:
812 return VisitActivationOperator(delegateData,
813 tfLiteContext,
814 tfLiteNode,
815 nodeIndex,
816 kTfLiteBuiltinHardSwish);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100817 case kTfLiteBuiltinL2Normalization:
818 return VisitL2NormalizationOperator(delegateData,
819 tfLiteContext,
820 tfLiteNode,
821 nodeIndex,
822 kTfLiteBuiltinL2Normalization);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100823 case kTfLiteBuiltinL2Pool2d:
824 return VisitPooling2dOperator(delegateData,
825 tfLiteContext,
826 tfLiteNode,
827 nodeIndex,
828 kTfLiteBuiltinL2Pool2d);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100829 case kTfLiteBuiltinLess:
830 return VisitComparisonOperator(delegateData,
831 tfLiteContext,
832 tfLiteNode,
833 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100834 kTfLiteBuiltinLess,
835 armnn::ComparisonOperation::Less);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100836 case kTfLiteBuiltinLessEqual:
837 return VisitComparisonOperator(delegateData,
838 tfLiteContext,
839 tfLiteNode,
840 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100841 kTfLiteBuiltinLessEqual,
842 armnn::ComparisonOperation::LessOrEqual);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100843 case kTfLiteBuiltinLogistic:
844 return VisitActivationOperator(delegateData,
845 tfLiteContext,
846 tfLiteNode,
847 nodeIndex,
848 kTfLiteBuiltinLogistic);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100849 case kTfLiteBuiltinLocalResponseNormalization:
850 return VisitLocalResponseNormalizationOperator(delegateData,
851 tfLiteContext,
852 tfLiteNode,
853 nodeIndex,
854 kTfLiteBuiltinLocalResponseNormalization);
855 case kTfLiteBuiltinLog:
856 return VisitElementwiseUnaryOperator(delegateData,
857 tfLiteContext,
858 tfLiteNode,
859 nodeIndex,
860 kTfLiteBuiltinLog,
861 armnn::UnaryOperation::Log);
862 case kTfLiteBuiltinLogicalAnd:
863 return VisitLogicalBinaryOperator(delegateData,
864 tfLiteContext,
865 tfLiteNode,
866 nodeIndex,
867 kTfLiteBuiltinLogicalAnd,
868 armnn::LogicalBinaryOperation::LogicalAnd);
869 case kTfLiteBuiltinLogicalNot:
870 return VisitElementwiseUnaryOperator(delegateData,
871 tfLiteContext,
872 tfLiteNode,
873 nodeIndex,
874 kTfLiteBuiltinLogicalNot,
875 armnn::UnaryOperation::LogicalNot);
876 case kTfLiteBuiltinLogicalOr:
877 return VisitLogicalBinaryOperator(delegateData,
878 tfLiteContext,
879 tfLiteNode,
880 nodeIndex,
881 kTfLiteBuiltinLogicalOr,
882 armnn::LogicalBinaryOperation::LogicalOr);
Teresa Charlin42362962023-04-28 14:23:33 +0100883 case kTfLiteBuiltinLogSoftmax:
884 return VisitSoftmaxOperator(delegateData,
885 tfLiteContext,
886 tfLiteNode,
887 nodeIndex,
888 kTfLiteBuiltinLogSoftmax);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100889 case kTfLiteBuiltinLstm:
890 return VisitLstmOperator(delegateData,
891 tfLiteContext,
892 tfLiteNode,
893 nodeIndex,
894 kTfLiteBuiltinLstm);
895 case kTfLiteBuiltinMaxPool2d:
896 return VisitPooling2dOperator(delegateData,
897 tfLiteContext,
898 tfLiteNode,
899 nodeIndex,
900 kTfLiteBuiltinMaxPool2d);
David Monahan6c53f9f2023-04-27 15:21:19 +0100901 case kTfLiteBuiltinMaximum:
902 return VisitElementwiseBinaryOperator(delegateData,
903 tfLiteContext,
904 tfLiteNode,
905 nodeIndex,
906 kTfLiteBuiltinMaximum);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100907 case kTfLiteBuiltinMean:
908 return VisitControlOperator(delegateData,
909 tfLiteContext,
910 tfLiteNode,
911 nodeIndex,
912 kTfLiteBuiltinMean);
David Monahan6c53f9f2023-04-27 15:21:19 +0100913 case kTfLiteBuiltinMinimum:
914 return VisitElementwiseBinaryOperator(delegateData,
915 tfLiteContext,
916 tfLiteNode,
917 nodeIndex,
918 kTfLiteBuiltinMinimum);
919 case kTfLiteBuiltinMul:
920 return VisitElementwiseBinaryOperator(delegateData,
921 tfLiteContext,
922 tfLiteNode,
923 nodeIndex,
924 kTfLiteBuiltinMul);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100925 case kTfLiteBuiltinNeg:
926 return VisitElementwiseUnaryOperator(delegateData,
927 tfLiteContext,
928 tfLiteNode,
929 nodeIndex,
930 kTfLiteBuiltinNeg,
931 armnn::UnaryOperation::Neg);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100932 case kTfLiteBuiltinNotEqual:
933 return VisitComparisonOperator(delegateData,
934 tfLiteContext,
935 tfLiteNode,
936 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100937 kTfLiteBuiltinNotEqual,
938 armnn::ComparisonOperation::NotEqual);
Teresa Charlinecebb0f2023-04-27 21:37:56 +0100939 case kTfLiteBuiltinPack:
940 return VisitPackOperator(delegateData,
941 tfLiteContext,
942 tfLiteNode,
943 nodeIndex,
944 kTfLiteBuiltinPack);
945 case kTfLiteBuiltinPad:
946 return VisitPadOperator(delegateData,
947 tfLiteContext,
948 tfLiteNode,
949 nodeIndex,
950 kTfLiteBuiltinPad);
951 case kTfLiteBuiltinPadv2:
952 return VisitPadOperator(delegateData,
953 tfLiteContext,
954 tfLiteNode,
955 nodeIndex,
956 kTfLiteBuiltinPadv2);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100957 case kTfLiteBuiltinPrelu:
958 return VisitPreluOperator(delegateData,
959 tfLiteContext,
960 tfLiteNode,
961 nodeIndex,
962 kTfLiteBuiltinPrelu);
Francis Murtagh36d94ef2023-04-28 14:05:43 +0100963 case kTfLiteBuiltinQuantize:
964 return VisitQuantizeOperator(delegateData,
965 tfLiteContext,
966 tfLiteNode,
967 nodeIndex,
968 kTfLiteBuiltinQuantize);
John Mcloughlin083586d2023-04-28 18:36:52 +0100969 case kTfLiteBuiltinReduceMax:
970 return VisitReduceOperator(delegateData,
971 tfLiteContext,
972 tfLiteNode,
973 nodeIndex,
974 kTfLiteBuiltinReduceMax);
975 case kTfLiteBuiltinReduceMin:
976 return VisitReduceOperator(delegateData,
977 tfLiteContext,
978 tfLiteNode,
979 nodeIndex,
980 kTfLiteBuiltinReduceMin);
981 case kTfLiteBuiltinReduceProd:
982 return VisitReduceOperator(delegateData,
983 tfLiteContext,
984 tfLiteNode,
985 nodeIndex,
986 kTfLiteBuiltinReduceProd);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100987 case kTfLiteBuiltinRelu:
988 return VisitActivationOperator(delegateData,
989 tfLiteContext,
990 tfLiteNode,
991 nodeIndex,
992 kTfLiteBuiltinRelu);
993 case kTfLiteBuiltinReluN1To1:
994 return VisitActivationOperator(delegateData,
995 tfLiteContext,
996 tfLiteNode,
997 nodeIndex,
998 kTfLiteBuiltinReluN1To1);
999 case kTfLiteBuiltinRelu6:
1000 return VisitActivationOperator(delegateData,
1001 tfLiteContext,
1002 tfLiteNode,
1003 nodeIndex,
1004 kTfLiteBuiltinRelu6);
Matthew Sloyanc49aacc2023-04-28 17:27:26 +01001005 case kTfLiteBuiltinReshape:
1006 return VisitReshapeOperator(delegateData,
1007 tfLiteContext,
1008 tfLiteNode,
1009 nodeIndex,
1010 kTfLiteBuiltinReshape);
John Mcloughlin083586d2023-04-28 18:36:52 +01001011 case kTfLiteBuiltinResizeNearestNeighbor:
1012 return VisitResizeOperator(delegateData,
1013 tfLiteContext,
1014 tfLiteNode,
1015 nodeIndex,
1016 kTfLiteBuiltinResizeNearestNeighbor);
1017 case kTfLiteBuiltinResizeBilinear:
1018 return VisitResizeOperator(delegateData,
1019 tfLiteContext,
1020 tfLiteNode,
1021 nodeIndex,
1022 kTfLiteBuiltinResizeBilinear);
Teresa Charlinf69ae562023-04-27 14:42:23 +01001023 case kTfLiteBuiltinRsqrt:
1024 return VisitElementwiseUnaryOperator(delegateData,
1025 tfLiteContext,
1026 tfLiteNode,
1027 nodeIndex,
1028 kTfLiteBuiltinRsqrt,
1029 armnn::UnaryOperation::Rsqrt);
John Mcloughlin0422cf22023-04-27 16:55:00 +01001030 case kTfLiteBuiltinShape:
1031 return VisitShapeOperator(delegateData,
1032 tfLiteContext,
1033 tfLiteNode,
1034 nodeIndex,
1035 kTfLiteBuiltinShape);
Teresa Charlinf69ae562023-04-27 14:42:23 +01001036 case kTfLiteBuiltinSin:
1037 return VisitElementwiseUnaryOperator(delegateData,
1038 tfLiteContext,
1039 tfLiteNode,
1040 nodeIndex,
1041 kTfLiteBuiltinSin,
1042 armnn::UnaryOperation::Sin);
Teresa Charlin86b03572023-04-28 13:19:12 +01001043 case kTfLiteBuiltinSlice:
1044 return VisitSliceOperator(delegateData,
1045 tfLiteContext,
1046 tfLiteNode,
1047 nodeIndex,
1048 kTfLiteBuiltinSlice);
Teresa Charlin42362962023-04-28 14:23:33 +01001049 case kTfLiteBuiltinSoftmax:
1050 return VisitSoftmaxOperator(delegateData,
1051 tfLiteContext,
1052 tfLiteNode,
1053 nodeIndex,
1054 kTfLiteBuiltinSoftmax);
Kevin May81b66f32023-04-26 14:55:36 +01001055 case kTfLiteBuiltinSpaceToBatchNd:
1056 return VisitSpaceToBatchNdOperator(delegateData,
1057 tfLiteContext,
1058 tfLiteNode,
1059 nodeIndex,
1060 kTfLiteBuiltinSpaceToBatchNd);
Teresa Charlin42362962023-04-28 14:23:33 +01001061 case kTfLiteBuiltinSpaceToDepth:
1062 return VisitSpaceToDepthOperator(delegateData,
1063 tfLiteContext,
1064 tfLiteNode,
1065 nodeIndex,
1066 kTfLiteBuiltinSpaceToDepth);
David Monahan6c53f9f2023-04-27 15:21:19 +01001067 case kTfLiteBuiltinSub:
1068 return VisitElementwiseBinaryOperator(delegateData,
1069 tfLiteContext,
1070 tfLiteNode,
1071 nodeIndex,
1072 kTfLiteBuiltinSub);
Teresa Charlinf69ae562023-04-27 14:42:23 +01001073 case kTfLiteBuiltinSqrt:
1074 return VisitElementwiseUnaryOperator(delegateData,
1075 tfLiteContext,
1076 tfLiteNode,
1077 nodeIndex,
1078 kTfLiteBuiltinSqrt,
1079 armnn::UnaryOperation::Sqrt);
Teresa Charlin86b03572023-04-28 13:19:12 +01001080 case kTfLiteBuiltinStridedSlice:
1081 return VisitStridedSliceOperator(delegateData,
1082 tfLiteContext,
1083 tfLiteNode,
1084 nodeIndex,
1085 kTfLiteBuiltinStridedSlice);
John Mcloughlin083586d2023-04-28 18:36:52 +01001086 case kTfLiteBuiltinSum:
1087 return VisitReduceOperator(delegateData,
1088 tfLiteContext,
1089 tfLiteNode,
1090 nodeIndex,
1091 kTfLiteBuiltinSum);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +01001092 case kTfLiteBuiltinTanh:
1093 return VisitActivationOperator(delegateData,
1094 tfLiteContext,
1095 tfLiteNode,
1096 nodeIndex,
1097 kTfLiteBuiltinTanh);
Teresa Charlin42362962023-04-28 14:23:33 +01001098 case kTfLiteBuiltinTranspose:
1099 return VisitTransposeOperator(delegateData,
1100 tfLiteContext,
1101 tfLiteNode,
1102 nodeIndex,
1103 kTfLiteBuiltinTranspose);
Francis Murtagh3a9e7ba2023-04-26 15:58:39 +01001104 case kTfLiteBuiltinTransposeConv:
1105 return VisitConvolutionOperator(delegateData,
1106 tfLiteContext,
1107 tfLiteNode,
1108 nodeIndex,
1109 kTfLiteBuiltinTransposeConv);
Teresa Charlinecebb0f2023-04-27 21:37:56 +01001110 case kTfLiteBuiltinUnpack:
1111 return VisitUnpackOperator(delegateData,
1112 tfLiteContext,
1113 tfLiteNode,
1114 nodeIndex,
1115 kTfLiteBuiltinUnpack);
Ryan OSheaac9607f2023-04-03 11:33:33 +01001116 default:
1117 return kTfLiteError;
1118 }
1119}
Francis Murtagh3a9e7ba2023-04-26 15:58:39 +01001120} // armnnOpaqueDelegate namespace