blob: 9e047f6a68a4c324626871802ccccade3184129a [file] [log] [blame]
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +00001//
Colm Donelan253d1bb2024-03-04 22:19:26 +00002// Copyright © 2023-2024 Arm Ltd and Contributors. All rights reserved.
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +00003// 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
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +00009#include "Activation.hpp"
10#include "ArgMinMax.hpp"
11#include "BatchMatMul.hpp"
12#include "BatchSpace.hpp"
Idriss Chaouchcbf79292023-09-08 11:18:16 +010013#include "BroadcastTo.hpp"
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +000014#include "Comparison.hpp"
15#include "Convolution.hpp"
16#include "Control.hpp"
17#include "ElementwiseBinary.hpp"
18#include "ElementwiseUnary.hpp"
19#include "Fill.hpp"
20#include "FullyConnected.hpp"
21#include "Gather.hpp"
22#include "GatherNd.hpp"
23#include "LogicalBinary.hpp"
24#include "Lstm.hpp"
25#include "Normalization.hpp"
26#include "Pack.hpp"
27#include "Pad.hpp"
28#include "Pooling.hpp"
29#include "Prelu.hpp"
30#include "Quantization.hpp"
31#include "Redefine.hpp"
32#include "Reduce.hpp"
33#include "Resize.hpp"
Tracy Narine7306bbe2023-07-17 16:06:26 +010034#include "ReverseV2.hpp"
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +000035#include "Round.hpp"
Kevin May93bbf002024-03-11 09:31:10 +000036#include "ScatterNd.hpp"
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +000037#include "Shape.hpp"
38#include "Slice.hpp"
39#include "StridedSlice.hpp"
40#include "Softmax.hpp"
41#include "SpaceDepth.hpp"
42#include "Split.hpp"
Tianle Cheng92ce35c2023-07-25 16:41:00 +010043#include "Tile.hpp"
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +000044#include "Transpose.hpp"
45#include "UnidirectionalSequenceLstm.hpp"
46#include "Unpack.hpp"
47
48#include <armnn/utility/IgnoreUnused.hpp>
49#include <armnnUtils/Filesystem.hpp>
50#include <armnn/utility/Timer.hpp>
51#include <flatbuffers/flatbuffers.h>
52#include <tensorflow/lite/context_util.h>
53#include <tensorflow/lite/schema/schema_generated.h>
54#include <tensorflow/lite/minimal_logging.h>
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +000055
56#include <algorithm>
57#include <iostream>
58#include <sstream>
Teresa Charlin19ad8162023-10-04 11:17:03 +010059#include <regex>
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +000060
61namespace armnnOpaqueDelegate
62{
63
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +010064static auto* g_delegate_plugin_ArmnnDelegatePlugin_ =
Ryan OShea59f8f652023-05-11 20:37:53 +010065 new tflite::delegates::DelegatePluginRegistry::Register("armnn_delegate",
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +010066 ArmnnDelegatePlugin::New);
67
Teresa Charlin19ad8162023-10-04 11:17:03 +010068armnnDelegate::DelegateOptions ParseArmNNSettings(const tflite::TFLiteSettings* tfLiteSettings)
69{
70 const tflite::ArmNNSettings* settings = tfLiteSettings->armnn_settings();
71 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(settings,
72 "The passed TFLiteSettings did not contain a valid ArmNNSettings");
73
74 // Extract settings fields
75 bool fastmath = settings->fastmath();
76 std::string backends_str = (settings->backends()) ? settings->backends()->str() : "";
77 const ::flatbuffers::String* additional_parameters = settings->additional_parameters();
78
79 // Build additional parameters string
80 std::string additional_parameters_str;
81 if (additional_parameters)
82 {
83 additional_parameters_str = additional_parameters->str();
84
85 // Apply a regex to remove spaces around the = and , signs
86 std::regex regex_equals_str("[ ]*=[ ]*");
87 std::regex regex_comma_str("[ ]*,[ ]*");
88 additional_parameters_str = std::regex_replace(additional_parameters_str, regex_equals_str, "=");
89 additional_parameters_str = std::regex_replace(additional_parameters_str, regex_comma_str, ",");
90 }
91
92 // Build a std::pair list of option names and values
93 std::vector<std::pair<std::string, std::string>> options;
94 options.emplace_back(std::pair<std::string, std::string>("backends", backends_str));
95 options.emplace_back(std::pair<std::string, std::string>("enable-fast-math", (fastmath) ? "true" : "false"));
96
97 std::stringstream additional_parameters_ss(additional_parameters_str);
98 while (additional_parameters_ss.good())
99 {
100 std::string option_str;
101 getline( additional_parameters_ss, option_str, ',' );
102 size_t n = option_str.find("=");
103 if (n != std::string::npos)
104 {
105 std::string name = option_str.substr(0, n);
106 std::string value = option_str.substr(n + 1, std::string::npos);
107 options.emplace_back(std::pair<std::string, std::string>(name, value));
108 }
109 }
110
111 // Build the key and value lists to pass into the constructor of the DelegateOptions
112 size_t num_options = options.size();
113 std::unique_ptr<const char*> options_keys = std::unique_ptr<const char*>(new const char*[num_options + 1]);
114 std::unique_ptr<const char*> options_values = std::unique_ptr<const char*>(new const char*[num_options + 1]);
115
116 for (size_t i=0; i<num_options; ++i)
117 {
118 options_keys.get()[i] = options[i].first.c_str();
119 options_values.get()[i] = options[i].second.c_str();
120 }
121
122 // Finally call the constructor
123 armnnDelegate::DelegateOptions delegateOptions = armnnDelegate::DelegateOptions(options_keys.get(),
124 options_values.get(),
125 num_options,
126 nullptr);
127
128 return delegateOptions;
129}
130
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +0000131ArmnnOpaqueDelegate::ArmnnOpaqueDelegate(armnnDelegate::DelegateOptions options)
132 : m_Options(std::move(options))
133{
134 // Configures logging for ARMNN
135 if (m_Options.IsLoggingEnabled())
136 {
137 armnn::ConfigureLogging(true, true, m_Options.GetLoggingSeverity());
138 }
139 // Create/Get the static ArmNN Runtime. Note that the m_Runtime will be shared by all armnn_delegate
140 // instances so the RuntimeOptions cannot be altered for different armnn_delegate instances.
141 m_Runtime = GetRuntime(m_Options.GetRuntimeOptions());
142 std::vector<armnn::BackendId> backends;
143 if (m_Runtime)
144 {
145 const armnn::BackendIdSet supportedDevices = m_Runtime->GetDeviceSpec().GetSupportedBackends();
146 for (auto& backend : m_Options.GetBackends())
147 {
148 if (std::find(supportedDevices.cbegin(), supportedDevices.cend(), backend) == supportedDevices.cend())
149 {
150 TFLITE_LOG_PROD(tflite::TFLITE_LOG_INFO,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100151 "TfLiteArmnnOpaqueDelegate: Requested unknown backend %s", backend.Get().c_str());
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +0000152 }
153 else
154 {
155 backends.push_back(backend);
Kevin May0425a372023-11-03 12:06:04 +0000156 TFLITE_LOG_PROD(tflite::TFLITE_LOG_INFO,
157 "TfLiteArmnnOpaqueDelegate: Added backend %s", backend.Get().c_str());
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +0000158 }
159 }
160 }
161
162 if (backends.empty())
163 {
164 // No known backend specified
165 throw armnn::InvalidArgumentException("TfLiteArmnnOpaqueDelegate: No known backend specified.");
166 }
167 m_Options.SetBackends(backends);
168
169 TFLITE_LOG_PROD_ONCE(tflite::TFLITE_LOG_INFO, "TfLiteArmnnOpaqueDelegate: Created TfLite ArmNN delegate.");
170}
171
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100172TfLiteStatus DoPrepare(TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueDelegate* tfLiteDelegate, void* data)
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100173{
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100174 // We are required to have the void* data parameter in the function signature, but we don't actually use it.
175 armnn::IgnoreUnused(data);
176
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100177 TfLiteIntArray* supportedOperators =
178 static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100179 (TfLiteOpaqueDelegateGetData(tfLiteDelegate))->IdentifyOperatorsToDelegate(tfLiteContext);
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100180 if(supportedOperators == nullptr)
181 {
182 return kTfLiteError;
183 }
184
185 // ArmNN Opaque Delegate Registration
186 TfLiteRegistrationExternal* kernelRegistration =
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +0100187 TfLiteRegistrationExternalCreate(kTfLiteBuiltinDelegate,
Ryan OShea59f8f652023-05-11 20:37:53 +0100188 "armnn_delegate",
Narumol Prangnawarat26654cb2023-05-03 16:08:11 +0100189 /*version=*/OPAQUE_DELEGATE_MAJOR_VERSION);
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100190 if(kernelRegistration == nullptr)
191 {
192 return kTfLiteError;
193 }
194
195 TfLiteRegistrationExternalSetInit(
196 kernelRegistration,
197 [](TfLiteOpaqueContext* tfLiteContext, const char* buffer, size_t length) -> void*
198 {
199 armnn::IgnoreUnused(length);
200 const TfLiteOpaqueDelegateParams* parameters =
201 reinterpret_cast<const TfLiteOpaqueDelegateParams*>(buffer);
202 if(parameters == nullptr)
203 {
204 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
205 "TfLiteArmnnOpaqueDelegate: Unable to get parameters.");
206 return nullptr;
207 }
208
209 return static_cast<void*>(
210 ArmnnSubgraph::Create(tfLiteContext,
211 parameters,
212 static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>(
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100213 parameters->delegate->opaque_delegate_builder->data)));
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100214 }
215 );
216
217 TfLiteRegistrationExternalSetFree(
218 kernelRegistration,
219 [](TfLiteOpaqueContext* tfLiteContext, void* buffer) -> void
220 {
221 armnn::IgnoreUnused(tfLiteContext);
222 if (buffer != nullptr)
223 {
224 delete static_cast<ArmnnSubgraph*>(buffer);
225 }
226 }
227 );
228
229 TfLiteRegistrationExternalSetPrepare(
230 kernelRegistration,
231 [](TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode) -> TfLiteStatus
232 {
233 void* userData = TfLiteOpaqueNodeGetUserData(tfLiteNode);
234 if (userData == nullptr)
235 {
236 return kTfLiteError;
237 }
238 return static_cast<ArmnnSubgraph*>(userData)->Prepare(tfLiteContext);
239 }
240 );
241
242 TfLiteRegistrationExternalSetInvoke(
243 kernelRegistration,
244 [](TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode) -> TfLiteStatus
245 {
246 void* userData = TfLiteOpaqueNodeGetUserData(tfLiteNode);
247 if (userData == nullptr)
248 {
249 return kTfLiteError;
250 }
251
252 return static_cast<ArmnnSubgraph*>(userData)->Invoke(tfLiteContext, tfLiteNode);
253 }
254 );
255
256 const TfLiteStatus status =
257 TfLiteOpaqueContextReplaceNodeSubsetsWithDelegateKernels(
258 tfLiteContext, kernelRegistration, supportedOperators, tfLiteDelegate);
259
260 TfLiteIntArrayFree(supportedOperators);
261 return status;
262}
263
Teresa Charlin3e4b6082023-10-19 19:13:29 +0100264TfLiteOpaqueDelegate* TfLiteArmnnOpaqueDelegateCreate(armnnDelegate::DelegateOptions options)
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +0000265{
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +0000266 auto* armnnDelegate = new ::armnnOpaqueDelegate::ArmnnOpaqueDelegate(options);
267 return TfLiteOpaqueDelegateCreate(armnnDelegate->GetDelegateBuilder());
268}
269
270::armnnDelegate::DelegateOptions TfLiteArmnnDelegateOptionsDefault()
271{
272 ::armnnDelegate::DelegateOptions options(armnn::Compute::CpuRef);
273 return options;
274}
275
276void TfLiteArmnnOpaqueDelegateDelete(TfLiteOpaqueDelegate* tfLiteDelegate)
277{
278 if (tfLiteDelegate != nullptr)
279 {
280 delete static_cast<::armnnOpaqueDelegate::ArmnnOpaqueDelegate*>(TfLiteOpaqueDelegateGetData(tfLiteDelegate));
281 TfLiteOpaqueDelegateDelete(tfLiteDelegate);
282 }
283}
284
Francis Murtaghc4fb0dd2023-03-16 17:01:56 +0000285const std::string ArmnnOpaqueDelegate::GetVersion() {
286 return OPAQUE_DELEGATE_VERSION;
287}
288
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100289TfLiteIntArray* ArmnnOpaqueDelegate::IdentifyOperatorsToDelegate(TfLiteOpaqueContext* tfLiteContext)
290{
291 TfLiteIntArray* executionPlan = nullptr;
292 if (TfLiteOpaqueContextGetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
293 {
294 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext, "TfLiteArmnnOpaqueDelegate: Unable to get graph execution plan.");
295 return nullptr;
296 }
297
298 // Delegate data with null network
299 DelegateData delegateData(m_Options.GetBackends());
300
301 TfLiteIntArray* nodesToDelegate = TfLiteIntArrayCreate(executionPlan->size);
302 if (nodesToDelegate == nullptr)
303 {
304 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
305 "TfLiteArmnnOpaqueDelegate: Unable to create int array from execution plan.");
306 return nullptr;
307 }
308 nodesToDelegate->size = 0;
309
310 std::set<int32_t> unsupportedOperators;
311
312 for (int i = 0; i < executionPlan->size; ++i)
313 {
314 const int nodeIndex = executionPlan->data[i];
315
316 // If TfLiteOpaqueNodes can be delegated to ArmNN
317 TfLiteOpaqueNode* tfLiteNode = nullptr;
318 TfLiteRegistrationExternal* tfLiteRegistration = nullptr;
319
320 if (TfLiteOpaqueContextGetNodeAndRegistration(
321 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
322 {
323 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
324 "TfLiteArmnnOpaqueDelegate: Unable to get node and registration for node %d.",
325 nodeIndex);
326 continue;
327 }
328
329 TfLiteStatus visitStatus;
330 try
331 {
332 visitStatus = ArmnnSubgraph::VisitNode(
333 delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex);
334 }
335 catch(std::exception& ex)
336 {
337 ARMNN_LOG(error) << "ArmNN Failed to visit node with error: " << ex.what();
338 visitStatus = kTfLiteError;
Ciara Sookarry39436152023-10-31 15:44:41 +0000339 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
340 "Exception text: %s",
341 ex.what());
Matthew Sloyan54cf0112023-04-03 16:32:57 +0100342 }
343
344 if (visitStatus != kTfLiteOk)
345 {
346 // node is not supported by ArmNN
347 unsupportedOperators.insert(TfLiteRegistrationExternalGetBuiltInCode(tfLiteRegistration));
348 continue;
349 }
350
351 nodesToDelegate->data[nodesToDelegate->size++] = nodeIndex;
352 }
353
354 for (std::set<int32_t>::iterator it=unsupportedOperators.begin(); it!=unsupportedOperators.end(); ++it)
355 {
356 TF_LITE_OPAQUE_KERNEL_LOG(tfLiteContext,
357 "Operator %s [%d] is not supported by armnn_opaque_delegate.",
358 tflite::EnumNameBuiltinOperator(tflite::BuiltinOperator(*it)),
359 *it);
360 }
361
362 if (!unsupportedOperators.empty() && m_Options.TfLiteRuntimeFallbackDisabled())
363 {
364 std::stringstream exMessage;
365 exMessage << "TfLiteArmnnOpaqueDelegate: There are unsupported operators in the model. ";
366 exMessage << "Not falling back to TfLite Runtime as fallback is disabled. ";
367 exMessage << "This should only be disabled under test conditions.";
368 throw armnn::Exception(exMessage.str());
369 }
370 if (nodesToDelegate->size == 0)
371 {
372 ARMNN_LOG(info) << "No operators in this model are supported by the Arm NN TfLite delegate." <<
373 " The model will be executed entirely by TfLite runtime.";
374 }
375
376 std::sort(&nodesToDelegate->data[0], &nodesToDelegate->data[nodesToDelegate->size]);
377 return nodesToDelegate;
378}
379
Colm Donelan253d1bb2024-03-04 22:19:26 +0000380ArmnnSubgraph::~ArmnnSubgraph()
381{
382 // The delegate holds its own Arm NN runtime so this is our last chance to print internal profiling data.
383 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
384 if (profiler && profiler->IsProfilingEnabled())
385 {
386 profiler->Print(std::cout);
387 }
388}
389
Ryan OSheaac9607f2023-04-03 11:33:33 +0100390TfLiteStatus ArmnnSubgraph::AddInputLayer(DelegateData& delegateData,
391 TfLiteOpaqueContext* tfLiteContext,
392 const TfLiteIntArray* inputs,
393 std::vector<armnn::BindingPointInfo>& inputBindings)
394{
395 const size_t numInputs = static_cast<size_t>(inputs->size);
396 for (unsigned int i = 0; i < numInputs; ++i)
397 {
398 const int32_t tensorId = inputs->data[i];
399 const TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, tensorId);
400
401 if(!tensor)
402 {
403 return kTfLiteError;
404 }
405
406 // Do not create bindings for constant inputs
407 if (TfLiteOpaqueTensorGetAllocationType(tensor) == kTfLiteMmapRo)
408 {
409 continue;
410 }
411
412 auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
413 armnn::IConnectableLayer* layer = delegateData.m_Network->AddInputLayer(bindingId);
414
415 auto tensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tensor);
416 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
417 outputSlot.SetTensorInfo(tensorInfo);
418
419 // Store for creating connections
420 delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] = &outputSlot;
421
422 inputBindings.push_back(std::make_pair(bindingId, tensorInfo));
423 }
424
425 return kTfLiteOk;
426}
427
428TfLiteStatus ArmnnSubgraph::AddOutputLayer(DelegateData& delegateData,
429 TfLiteOpaqueContext* tfLiteContext,
430 const TfLiteIntArray* outputs,
431 std::vector<armnn::BindingPointInfo>& outputBindings)
432{
433 const size_t numOutputs = static_cast<size_t>(outputs->size);
434 for (unsigned int i = 0; i < numOutputs; ++i)
435 {
436 const int32_t tensorId = outputs->data[i];
437 const TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, tensorId);
438
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100439 if(!IsValid(tensor))
Ryan OSheaac9607f2023-04-03 11:33:33 +0100440 {
441 return kTfLiteError;
442 }
443
444 auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
445 armnn::IConnectableLayer* layer = delegateData.m_Network->AddOutputLayer(bindingId);
446
447 auto tensorInfo = GetTensorInfoForTfLiteOpaqueTensor(tensor);
Ryan OSheac229b3f2023-06-27 22:34:54 +0100448
449 if (delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] == nullptr)
450 {
451 return kTfLiteError;
452 }
453
Ryan OSheaac9607f2023-04-03 11:33:33 +0100454 delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)]->Connect(layer->GetInputSlot(0));
455 outputBindings.push_back(std::make_pair(bindingId, tensorInfo));
456 }
457
458 return kTfLiteOk;
459}
460
461ArmnnSubgraph* ArmnnSubgraph::Create(TfLiteOpaqueContext* tfLiteContext,
462 const TfLiteOpaqueDelegateParams* parameters,
463 const ArmnnOpaqueDelegate* delegate)
464{
465 const auto startTime = armnn::GetTimeNow();
466 ARMNN_LOG(info) << "ArmnnSubgraph creation";
467
468 TfLiteIntArray* executionPlan;
469 if (TfLiteOpaqueContextGetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
470 {
471 return nullptr;
472 }
473
474 // Initialize DelegateData holds network and output slots information
475 DelegateData delegateData(delegate->m_Options.GetBackends());
476
477 // Build ArmNN Network
John Mcloughlinc5ee0d72023-03-24 12:07:25 +0000478 armnn::NetworkOptions networkOptions = delegate->m_Options.GetOptimizerOptions().GetModelOptions();
Ryan OSheaac9607f2023-04-03 11:33:33 +0100479 armnn::NetworkId networkId;
480 delegateData.m_Network = armnn::INetwork::Create(networkOptions);
481
482 delegateData.m_OutputSlotForNode = std::vector<armnn::IOutputSlot*>(
483 TfLiteOpaqueContextGetNumTensors(tfLiteContext), nullptr);
484
485 std::vector<armnn::BindingPointInfo> inputBindings;
486 std::vector<armnn::BindingPointInfo> outputBindings;
487
488 // Add input layer
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100489 if (AddInputLayer(delegateData, tfLiteContext, parameters->input_tensors, inputBindings) != kTfLiteOk)
Ryan OSheaac9607f2023-04-03 11:33:33 +0100490 {
491 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to add Inputs to the network!");
492 }
493
494 // Parse TfLite delegate nodes to ArmNN
495 const auto parseStartTime = armnn::GetTimeNow();
496 for (int i = 0; i < parameters->nodes_to_replace->size; ++i)
497 {
498 const int nodeIndex = parameters->nodes_to_replace->data[i];
499
500 TfLiteOpaqueNode* tfLiteNode = nullptr;
501 TfLiteRegistrationExternal* tfLiteRegistration = nullptr;
502 if (TfLiteOpaqueContextGetNodeAndRegistration(
503 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
504 {
505 throw armnn::Exception(&"TfLiteArmnnOpaqueDelegate: Unable to get node registration: " [ nodeIndex]);
506 }
507
508 if (VisitNode(delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex) != kTfLiteOk)
509 {
510 throw armnn::Exception(&"TfLiteArmnnOpaqueDelegate: Unable to parse node: " [ nodeIndex]);
511 }
512 }
513 ARMNN_LOG(info) << "Parse nodes to ArmNN time: " << std::setprecision(2)
514 << std::fixed << armnn::GetTimeDuration(parseStartTime).count() << " ms";
515
516 // Add Output layer
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100517 if (AddOutputLayer(delegateData, tfLiteContext, parameters->output_tensors, outputBindings) != kTfLiteOk)
Ryan OSheaac9607f2023-04-03 11:33:33 +0100518 {
519 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to add Outputs to the network!");
520 }
521
522 // Optimize ArmNN network
523 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
524 try
525 {
526 const auto optimizeStartTime = armnn::GetTimeNow();
527 optNet = armnn::Optimize(*(delegateData.m_Network.get()),
528 delegate->m_Options.GetBackends(),
529 delegate->m_Runtime->GetDeviceSpec(),
530 delegate->m_Options.GetOptimizerOptions());
531 ARMNN_LOG(info) << "Optimize ArmnnSubgraph time: " << std::setprecision(2)
532 << std::fixed << armnn::GetTimeDuration(optimizeStartTime).count() << " ms";
533 }
534 catch (std::exception& ex)
535 {
536 std::stringstream exMessage;
537 exMessage << "TfLiteArmnnOpaqueDelegate: Exception (" << ex.what() << ") caught from optimize.";
538 throw armnn::Exception(exMessage.str());
539 }
540 if (!optNet)
541 {
542 // Optimize failed
543 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to optimize the network!");
544 }
545
546 // If set, we will serialize the optimized model into a dot file.
547 const std::string serializeToDotFile = delegate->m_Options.GetSerializeToDot();
548 if (!serializeToDotFile.empty())
549 {
550 ARMNN_LOG(info) << "Writing graph to dot file: " << serializeToDotFile;
551 fs::path filename = serializeToDotFile;
552 std::fstream file(filename.c_str(), std::ios_base::out);
553 optNet->SerializeToDot(file);
554 }
555
556 try
557 {
558 const auto loadStartTime = armnn::GetTimeNow();
559
560 // Load graph into runtime
561 std::string errorMessage;
562 armnn::Status loadingStatus;
563 armnn::MemorySource inputSource = armnn::MemorySource::Undefined;
564 armnn::MemorySource outputSource = armnn::MemorySource::Undefined;
565 // There's a bit of an assumption here that the delegate will only support Malloc memory source.
John Mcloughlinc5ee0d72023-03-24 12:07:25 +0000566 if (delegate->m_Options.GetOptimizerOptions().GetImportEnabled())
Ryan OSheaac9607f2023-04-03 11:33:33 +0100567 {
568 inputSource = armnn::MemorySource::Malloc;
569 }
John Mcloughlinc5ee0d72023-03-24 12:07:25 +0000570 if (delegate->m_Options.GetOptimizerOptions().GetExportEnabled())
Ryan OSheaac9607f2023-04-03 11:33:33 +0100571 {
572 outputSource = armnn::MemorySource::Malloc;
573 }
574 armnn::INetworkProperties networkProperties(false,
575 inputSource,
576 outputSource,
577 delegate->m_Options.GetInternalProfilingState(),
578 delegate->m_Options.GetInternalProfilingDetail());
579 loadingStatus = delegate->m_Runtime->LoadNetwork(networkId,
580 std::move(optNet),
581 errorMessage,
582 networkProperties);
583 if (loadingStatus != armnn::Status::Success)
584 {
585 // Network load failed.
586 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Network could not be loaded: " + errorMessage);
587 }
588
589 ARMNN_LOG(info) << "Load ArmnnSubgraph time: " << std::setprecision(2)
590 << std::fixed << armnn::GetTimeDuration(loadStartTime).count() << " ms";
591 }
592 catch (std::exception& ex)
593 {
594 std::stringstream exMessage;
595 exMessage << "TfLiteArmnnOpaqueDelegate: Exception (" << ex.what() << ") caught from LoadNetwork.";
596 throw armnn::Exception(exMessage.str());
597 }
598
599 // Register debug callback function
600 if (delegate->m_Options.GetDebugCallbackFunction().has_value())
601 {
602 delegate->m_Runtime->RegisterDebugCallback(networkId, delegate->m_Options.GetDebugCallbackFunction().value());
603 }
604
605 ARMNN_LOG(info) << "Overall ArmnnSubgraph creation time: " << std::setprecision(2)
606 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms\n";
607
608 // Create a new SubGraph with networkId and runtime
609 return new ArmnnSubgraph(networkId, delegate->m_Runtime, inputBindings, outputBindings);
610}
611
612TfLiteStatus ArmnnSubgraph::Prepare(TfLiteOpaqueContext* tfLiteContext)
613{
614 armnn::IgnoreUnused(tfLiteContext);
615 return kTfLiteOk;
616}
617
618TfLiteStatus ArmnnSubgraph::Invoke(TfLiteOpaqueContext* tfLiteContext, TfLiteOpaqueNode* tfLiteNode)
619{
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100620 // Get array of input indices, inputIndexArray is set from the TfLiteOpaqueNodeInputs function
621 // This function turns inputIndexArray into an int array of indices. These indices point to the tensors for
622 // each input slot in the node.
623 const int* inputIndexArray;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100624 int numInputs;
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100625 if(TfLiteOpaqueNodeInputs(tfLiteNode, &inputIndexArray, &numInputs) != kTfLiteOk)
Ryan OSheaac9607f2023-04-03 11:33:33 +0100626 {
627 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to load subgraph inputs!");
628 }
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100629 // Prepare inputs
630 armnn::InputTensors inputTensors;
631 size_t inputIndex = 0;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100632 for (int inputIdx = 0; inputIdx < numInputs; inputIdx++)
633 {
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100634 TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, inputIndexArray[inputIdx]);
Ryan OSheaac9607f2023-04-03 11:33:33 +0100635
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100636 if(!IsValid(tensor))
Ryan OSheaac9607f2023-04-03 11:33:33 +0100637 {
638 return kTfLiteError;
639 }
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100640 // If tensor is not read only
Ryan OSheaac9607f2023-04-03 11:33:33 +0100641 if (TfLiteOpaqueTensorGetAllocationType(tensor) != kTfLiteMmapRo)
642 {
643 const armnn::BindingPointInfo& inputBinding = m_InputBindings[inputIndex];
644 armnn::TensorInfo inputTensorInfo = inputBinding.second;
645 inputTensorInfo.SetConstant(true);
646 const armnn::ConstTensor inputTensor(inputTensorInfo, TfLiteOpaqueTensorData(tensor));
Narumol Prangnawarat46e574e2023-05-05 16:39:05 +0100647 inputTensors.emplace_back(inputIndexArray[inputIdx], inputTensor);
Ryan OSheaac9607f2023-04-03 11:33:33 +0100648
649 ++inputIndex;
650 }
651 }
652
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100653 // Get array of output indices, outputIndexArray is set from the TfLiteOpaqueNodeOutputs function
654 // This function turns outputIndexArray into an int array of indices. These indices point to the tensors for
655 // each output slot in the node.
656 const int* outputIndexArray;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100657 int numOutputs;
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100658 if(TfLiteOpaqueNodeOutputs(tfLiteNode, &outputIndexArray, &numOutputs) != kTfLiteOk)
Ryan OSheaac9607f2023-04-03 11:33:33 +0100659 {
660 throw armnn::Exception("TfLiteArmnnOpaqueDelegate: Unable to load subgraph outputs!");
661 }
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100662 // Assign the tensors from the outputIndexArray to the armnn BindingPointInfo
663 armnn::OutputTensors outputTensors;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100664 for (int outputIdx = 0; outputIdx < numOutputs; outputIdx++)
665 {
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100666 const armnn::BindingPointInfo& outputBinding = m_OutputBindings[outputIdx];
667 TfLiteOpaqueTensor* tensor = TfLiteOpaqueContextGetOpaqueTensor(tfLiteContext, outputIndexArray[outputIdx]);
668 if(!IsValid(tensor))
Ryan OSheaac9607f2023-04-03 11:33:33 +0100669 {
670 return kTfLiteError;
671 }
672
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100673 const armnn::Tensor outputTensor(outputBinding.second, reinterpret_cast<TfLiteTensor*>(tensor)->data
674 .data);
675 outputTensors.emplace_back(outputIndexArray[outputIdx], outputTensor);
Ryan OSheaac9607f2023-04-03 11:33:33 +0100676 }
677
678 // Run graph
David Monahan727d0172023-10-04 10:16:24 +0100679 try
Ryan OSheaac9607f2023-04-03 11:33:33 +0100680 {
David Monahan727d0172023-10-04 10:16:24 +0100681 auto status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
David Monahan727d0172023-10-04 10:16:24 +0100682 return (status == armnn::Status::Success) ? kTfLiteOk : kTfLiteError;
Ryan OSheaac9607f2023-04-03 11:33:33 +0100683 }
David Monahan727d0172023-10-04 10:16:24 +0100684 catch (armnn::InvalidArgumentException& ex)
685 {
David Monahan8df6bf32023-11-10 09:55:33 +0000686 std::stringstream exMessage;
687 exMessage << "ArmNN Failed to EnqueueWorkload with error: " << ex.what();
688 ARMNN_LOG(error) << exMessage.str();
689 TFLITE_LOG_PROD_ONCE(tflite::TFLITE_LOG_INFO, exMessage.str().c_str());
David Monahan727d0172023-10-04 10:16:24 +0100690 // This should really be kTfLiteDelegateError but the Delegate Test Suite expects kTfLiteError so we return
691 // that instead
692 return kTfLiteError;
693 }
694
Ryan OSheaac9607f2023-04-03 11:33:33 +0100695}
696
697TfLiteStatus ArmnnSubgraph::VisitNode(DelegateData& delegateData,
698 TfLiteOpaqueContext* tfLiteContext,
699 TfLiteRegistrationExternal* tfLiteRegistration,
700 TfLiteOpaqueNode* tfLiteNode,
701 int nodeIndex)
702{
703 switch (TfLiteRegistrationExternalGetBuiltInCode(tfLiteRegistration))
704 {
Teresa Charlinf69ae562023-04-27 14:42:23 +0100705 case kTfLiteBuiltinAbs:
706 return VisitElementwiseUnaryOperator(delegateData,
707 tfLiteContext,
708 tfLiteNode,
709 nodeIndex,
710 kTfLiteBuiltinAbs,
711 armnn::UnaryOperation::Abs);
David Monahan6c53f9f2023-04-27 15:21:19 +0100712 case kTfLiteBuiltinAdd:
713 return VisitElementwiseBinaryOperator(delegateData,
714 tfLiteContext,
715 tfLiteNode,
716 nodeIndex,
717 kTfLiteBuiltinAdd);
John Mcloughlin559d9092023-04-26 20:14:47 +0100718 case kTfLiteBuiltinArgMax:
719 return VisitArgMinMaxOperator(delegateData,
720 tfLiteContext,
721 tfLiteNode,
722 nodeIndex,
723 kTfLiteBuiltinArgMax);
724 case kTfLiteBuiltinArgMin:
725 return VisitArgMinMaxOperator(delegateData,
726 tfLiteContext,
727 tfLiteNode,
728 nodeIndex,
729 kTfLiteBuiltinArgMin);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100730 case kTfLiteBuiltinAveragePool2d:
731 return VisitPooling2dOperator(delegateData,
732 tfLiteContext,
733 tfLiteNode,
734 nodeIndex,
735 kTfLiteBuiltinAveragePool2d);
John Mcloughlin0422cf22023-04-27 16:55:00 +0100736 case kTfLiteBuiltinBatchMatmul:
737 return VisitBatchMatMulOperator(delegateData,
738 tfLiteContext,
739 tfLiteNode,
740 nodeIndex,
741 kTfLiteBuiltinBatchMatmul);
Idriss Chaouchcbf79292023-09-08 11:18:16 +0100742 case kTfLiteBuiltinBroadcastTo:
743 return VisitBroadcastToOperator(delegateData,
744 tfLiteContext,
745 tfLiteNode,
746 nodeIndex,
747 kTfLiteBuiltinBroadcastTo);
Kevin May81b66f32023-04-26 14:55:36 +0100748 case kTfLiteBuiltinBatchToSpaceNd:
749 return VisitBatchToSpaceNdOperator(delegateData,
750 tfLiteContext,
751 tfLiteNode,
752 nodeIndex,
753 kTfLiteBuiltinBatchToSpaceNd);
Ryan OSheaa37ccb02023-04-11 10:54:07 +0100754 case kTfLiteBuiltinCast:
755 return VisitCastOperator(delegateData,
756 tfLiteContext,
757 tfLiteNode,
758 nodeIndex,
759 kTfLiteBuiltinCast);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100760 case kTfLiteBuiltinCeil:
761 return VisitElementwiseUnaryOperator(delegateData,
762 tfLiteContext,
763 tfLiteNode,
764 nodeIndex,
765 kTfLiteBuiltinCeil,
766 armnn::UnaryOperation::Ceil);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100767 case kTfLiteBuiltinConcatenation:
768 return VisitControlOperator(delegateData,
769 tfLiteContext,
770 tfLiteNode,
771 nodeIndex,
772 kTfLiteBuiltinConcatenation);
Matthew Sloyan080ffd82023-04-24 12:53:04 +0100773 case kTfLiteBuiltinConv2d:
774 return VisitConvolutionOperator(delegateData,
775 tfLiteContext,
776 tfLiteNode,
777 nodeIndex,
778 kTfLiteBuiltinConv2d);
Francis Murtagh3a9e7ba2023-04-26 15:58:39 +0100779 case kTfLiteBuiltinConv3d:
780 return VisitConvolutionOperator(delegateData,
781 tfLiteContext,
782 tfLiteNode,
783 nodeIndex,
784 kTfLiteBuiltinConv3d);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100785 case kTfLiteBuiltinCustom:
786 {
787 // Custom operators are defined by the name rather than the builtin code.
788 // Parse the custom_name param in the registration to point to the correct visitor function.
789 std::string customOperatorName = TfLiteRegistrationExternalGetCustomName(tfLiteRegistration);
790 if ( customOperatorName == "AveragePool3D" )
791 {
792 return VisitPooling3dOperator(delegateData,
793 tfLiteContext,
794 tfLiteNode,
795 nodeIndex,
796 customOperatorName);
797 }
798 else if (customOperatorName == "MaxPool3D")
799 {
800 return VisitPooling3dOperator(delegateData,
801 tfLiteContext,
802 tfLiteNode,
803 nodeIndex,
804 customOperatorName);
805 }
806 // Invalid or unsupported custom operator
807 return kTfLiteError;
808 }
Matthew Sloyan080ffd82023-04-24 12:53:04 +0100809 case kTfLiteBuiltinDepthwiseConv2d:
810 return VisitConvolutionOperator(delegateData,
811 tfLiteContext,
812 tfLiteNode,
813 nodeIndex,
814 kTfLiteBuiltinDepthwiseConv2d);
Francis Murtagh36d94ef2023-04-28 14:05:43 +0100815 case kTfLiteBuiltinDequantize:
816 return VisitDequantizeOperator(delegateData,
817 tfLiteContext,
818 tfLiteNode,
819 nodeIndex,
820 kTfLiteBuiltinDequantize);
David Monahan6c53f9f2023-04-27 15:21:19 +0100821 case kTfLiteBuiltinDiv:
822 return VisitElementwiseBinaryOperator(delegateData,
823 tfLiteContext,
824 tfLiteNode,
825 nodeIndex,
826 kTfLiteBuiltinDiv);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100827 case kTfLiteBuiltinEqual:
828 return VisitComparisonOperator(delegateData,
829 tfLiteContext,
830 tfLiteNode,
831 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100832 kTfLiteBuiltinEqual,
833 armnn::ComparisonOperation::Equal);
Teresa Charlin42362962023-04-28 14:23:33 +0100834 case kTfLiteBuiltinDepthToSpace:
835 return VisitDepthToSpaceOperator(delegateData,
836 tfLiteContext,
837 tfLiteNode,
838 nodeIndex,
839 kTfLiteBuiltinDepthToSpace);
840 case kTfLiteBuiltinElu:
841 return VisitActivationOperator(delegateData,
842 tfLiteContext,
843 tfLiteNode,
844 nodeIndex,
845 kTfLiteBuiltinElu);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100846 case kTfLiteBuiltinExp:
847 return VisitElementwiseUnaryOperator(delegateData,
848 tfLiteContext,
849 tfLiteNode,
850 nodeIndex,
851 kTfLiteBuiltinExp,
852 armnn::UnaryOperation::Exp);
Matthew Sloyan3504e422023-05-03 13:53:02 +0100853 case kTfLiteBuiltinExpandDims:
854 return VisitExpandDimsOperator(delegateData,
855 tfLiteContext,
856 tfLiteNode,
857 nodeIndex,
858 kTfLiteBuiltinExpandDims);
Ryan OShea59f8f652023-05-11 20:37:53 +0100859 case kTfLiteBuiltinFill:
860 return VisitFillOperator(delegateData,
861 tfLiteContext,
862 tfLiteNode,
863 nodeIndex,
864 kTfLiteBuiltinFill);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100865 case kTfLiteBuiltinFloor:
866 return VisitFloorOperator(delegateData,
867 tfLiteContext,
868 tfLiteNode,
869 nodeIndex,
870 kTfLiteBuiltinFloor);
David Monahan6c53f9f2023-04-27 15:21:19 +0100871 case kTfLiteBuiltinFloorDiv:
872 return VisitElementwiseBinaryOperator(delegateData,
873 tfLiteContext,
874 tfLiteNode,
875 nodeIndex,
876 kTfLiteBuiltinFloorDiv);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100877 case kTfLiteBuiltinFullyConnected:
878 return VisitFullyConnectedOperator(delegateData,
879 tfLiteContext,
880 tfLiteNode,
881 nodeIndex,
882 kTfLiteBuiltinFullyConnected);
Kevin Mayb2831c52023-04-26 17:27:24 +0100883 case kTfLiteBuiltinGather:
884 return VisitGatherOperator(delegateData,
885 tfLiteContext,
886 tfLiteNode,
887 nodeIndex,
888 kTfLiteBuiltinGather);
889 case kTfLiteBuiltinGatherNd:
890 return VisitGatherNdOperator(delegateData,
891 tfLiteContext,
892 tfLiteNode,
893 nodeIndex,
894 kTfLiteBuiltinGatherNd);
Teresa Charlin077cddb2023-09-15 15:19:21 +0100895 case kTfLiteBuiltinGelu:
896 return VisitActivationOperator(delegateData,
897 tfLiteContext,
898 tfLiteNode,
899 nodeIndex,
900 kTfLiteBuiltinGelu);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100901 case kTfLiteBuiltinGreater:
902 return VisitComparisonOperator(delegateData,
903 tfLiteContext,
904 tfLiteNode,
905 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100906 kTfLiteBuiltinGreater,
907 armnn::ComparisonOperation::Greater);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100908 case kTfLiteBuiltinGreaterEqual:
909 return VisitComparisonOperator(delegateData,
910 tfLiteContext,
911 tfLiteNode,
912 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100913 kTfLiteBuiltinGreaterEqual,
914 armnn::ComparisonOperation::GreaterOrEqual);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100915 case kTfLiteBuiltinHardSwish:
916 return VisitActivationOperator(delegateData,
917 tfLiteContext,
918 tfLiteNode,
919 nodeIndex,
920 kTfLiteBuiltinHardSwish);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100921 case kTfLiteBuiltinL2Normalization:
922 return VisitL2NormalizationOperator(delegateData,
923 tfLiteContext,
924 tfLiteNode,
925 nodeIndex,
926 kTfLiteBuiltinL2Normalization);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100927 case kTfLiteBuiltinL2Pool2d:
928 return VisitPooling2dOperator(delegateData,
929 tfLiteContext,
930 tfLiteNode,
931 nodeIndex,
932 kTfLiteBuiltinL2Pool2d);
Tianle Chengae931732023-07-28 11:53:04 +0100933 case kTfLiteBuiltinLeakyRelu:
934 return VisitActivationOperator(delegateData,
935 tfLiteContext,
936 tfLiteNode,
937 nodeIndex,
938 kTfLiteBuiltinLeakyRelu);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100939 case kTfLiteBuiltinLess:
940 return VisitComparisonOperator(delegateData,
941 tfLiteContext,
942 tfLiteNode,
943 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100944 kTfLiteBuiltinLess,
945 armnn::ComparisonOperation::Less);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +0100946 case kTfLiteBuiltinLessEqual:
947 return VisitComparisonOperator(delegateData,
948 tfLiteContext,
949 tfLiteNode,
950 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +0100951 kTfLiteBuiltinLessEqual,
952 armnn::ComparisonOperation::LessOrEqual);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +0100953 case kTfLiteBuiltinLogistic:
954 return VisitActivationOperator(delegateData,
955 tfLiteContext,
956 tfLiteNode,
957 nodeIndex,
958 kTfLiteBuiltinLogistic);
Teresa Charlinf69ae562023-04-27 14:42:23 +0100959 case kTfLiteBuiltinLocalResponseNormalization:
960 return VisitLocalResponseNormalizationOperator(delegateData,
961 tfLiteContext,
962 tfLiteNode,
963 nodeIndex,
964 kTfLiteBuiltinLocalResponseNormalization);
965 case kTfLiteBuiltinLog:
966 return VisitElementwiseUnaryOperator(delegateData,
967 tfLiteContext,
968 tfLiteNode,
969 nodeIndex,
970 kTfLiteBuiltinLog,
971 armnn::UnaryOperation::Log);
972 case kTfLiteBuiltinLogicalAnd:
973 return VisitLogicalBinaryOperator(delegateData,
974 tfLiteContext,
975 tfLiteNode,
976 nodeIndex,
977 kTfLiteBuiltinLogicalAnd,
978 armnn::LogicalBinaryOperation::LogicalAnd);
979 case kTfLiteBuiltinLogicalNot:
980 return VisitElementwiseUnaryOperator(delegateData,
981 tfLiteContext,
982 tfLiteNode,
983 nodeIndex,
984 kTfLiteBuiltinLogicalNot,
985 armnn::UnaryOperation::LogicalNot);
986 case kTfLiteBuiltinLogicalOr:
987 return VisitLogicalBinaryOperator(delegateData,
988 tfLiteContext,
989 tfLiteNode,
990 nodeIndex,
991 kTfLiteBuiltinLogicalOr,
992 armnn::LogicalBinaryOperation::LogicalOr);
Teresa Charlin42362962023-04-28 14:23:33 +0100993 case kTfLiteBuiltinLogSoftmax:
994 return VisitSoftmaxOperator(delegateData,
995 tfLiteContext,
996 tfLiteNode,
997 nodeIndex,
998 kTfLiteBuiltinLogSoftmax);
Matthew Sloyan48ec8132023-04-27 17:04:47 +0100999 case kTfLiteBuiltinLstm:
1000 return VisitLstmOperator(delegateData,
1001 tfLiteContext,
1002 tfLiteNode,
1003 nodeIndex,
1004 kTfLiteBuiltinLstm);
1005 case kTfLiteBuiltinMaxPool2d:
1006 return VisitPooling2dOperator(delegateData,
1007 tfLiteContext,
1008 tfLiteNode,
1009 nodeIndex,
1010 kTfLiteBuiltinMaxPool2d);
David Monahan6c53f9f2023-04-27 15:21:19 +01001011 case kTfLiteBuiltinMaximum:
1012 return VisitElementwiseBinaryOperator(delegateData,
1013 tfLiteContext,
1014 tfLiteNode,
1015 nodeIndex,
1016 kTfLiteBuiltinMaximum);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +01001017 case kTfLiteBuiltinMean:
1018 return VisitControlOperator(delegateData,
1019 tfLiteContext,
1020 tfLiteNode,
1021 nodeIndex,
1022 kTfLiteBuiltinMean);
David Monahan6c53f9f2023-04-27 15:21:19 +01001023 case kTfLiteBuiltinMinimum:
1024 return VisitElementwiseBinaryOperator(delegateData,
1025 tfLiteContext,
1026 tfLiteNode,
1027 nodeIndex,
1028 kTfLiteBuiltinMinimum);
Ryan OShea59f8f652023-05-11 20:37:53 +01001029 case kTfLiteBuiltinMirrorPad:
1030 return VisitPadOperator(delegateData,
1031 tfLiteContext,
1032 tfLiteNode,
1033 nodeIndex,
1034 kTfLiteBuiltinMirrorPad);
David Monahan6c53f9f2023-04-27 15:21:19 +01001035 case kTfLiteBuiltinMul:
1036 return VisitElementwiseBinaryOperator(delegateData,
1037 tfLiteContext,
1038 tfLiteNode,
1039 nodeIndex,
1040 kTfLiteBuiltinMul);
Teresa Charlinf69ae562023-04-27 14:42:23 +01001041 case kTfLiteBuiltinNeg:
1042 return VisitElementwiseUnaryOperator(delegateData,
1043 tfLiteContext,
1044 tfLiteNode,
1045 nodeIndex,
1046 kTfLiteBuiltinNeg,
1047 armnn::UnaryOperation::Neg);
Matthew Sloyan2b04ec32023-04-26 11:42:46 +01001048 case kTfLiteBuiltinNotEqual:
1049 return VisitComparisonOperator(delegateData,
1050 tfLiteContext,
1051 tfLiteNode,
1052 nodeIndex,
Teresa Charlinf69ae562023-04-27 14:42:23 +01001053 kTfLiteBuiltinNotEqual,
1054 armnn::ComparisonOperation::NotEqual);
Teresa Charlinecebb0f2023-04-27 21:37:56 +01001055 case kTfLiteBuiltinPack:
1056 return VisitPackOperator(delegateData,
1057 tfLiteContext,
1058 tfLiteNode,
1059 nodeIndex,
1060 kTfLiteBuiltinPack);
1061 case kTfLiteBuiltinPad:
1062 return VisitPadOperator(delegateData,
1063 tfLiteContext,
1064 tfLiteNode,
1065 nodeIndex,
1066 kTfLiteBuiltinPad);
1067 case kTfLiteBuiltinPadv2:
1068 return VisitPadOperator(delegateData,
1069 tfLiteContext,
1070 tfLiteNode,
1071 nodeIndex,
1072 kTfLiteBuiltinPadv2);
John Mcloughlin0ec00872023-05-15 17:03:49 +01001073 case kTfLiteBuiltinPow:
1074 return VisitElementwiseBinaryOperator(delegateData,
1075 tfLiteContext,
1076 tfLiteNode,
1077 nodeIndex,
1078 kTfLiteBuiltinPow);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +01001079 case kTfLiteBuiltinPrelu:
1080 return VisitPreluOperator(delegateData,
1081 tfLiteContext,
1082 tfLiteNode,
1083 nodeIndex,
1084 kTfLiteBuiltinPrelu);
Francis Murtagh36d94ef2023-04-28 14:05:43 +01001085 case kTfLiteBuiltinQuantize:
1086 return VisitQuantizeOperator(delegateData,
1087 tfLiteContext,
1088 tfLiteNode,
1089 nodeIndex,
1090 kTfLiteBuiltinQuantize);
John Mcloughlin083586d2023-04-28 18:36:52 +01001091 case kTfLiteBuiltinReduceMax:
1092 return VisitReduceOperator(delegateData,
1093 tfLiteContext,
1094 tfLiteNode,
1095 nodeIndex,
1096 kTfLiteBuiltinReduceMax);
1097 case kTfLiteBuiltinReduceMin:
1098 return VisitReduceOperator(delegateData,
1099 tfLiteContext,
1100 tfLiteNode,
1101 nodeIndex,
1102 kTfLiteBuiltinReduceMin);
1103 case kTfLiteBuiltinReduceProd:
1104 return VisitReduceOperator(delegateData,
1105 tfLiteContext,
1106 tfLiteNode,
1107 nodeIndex,
1108 kTfLiteBuiltinReduceProd);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +01001109 case kTfLiteBuiltinRelu:
1110 return VisitActivationOperator(delegateData,
1111 tfLiteContext,
1112 tfLiteNode,
1113 nodeIndex,
1114 kTfLiteBuiltinRelu);
1115 case kTfLiteBuiltinReluN1To1:
1116 return VisitActivationOperator(delegateData,
1117 tfLiteContext,
1118 tfLiteNode,
1119 nodeIndex,
1120 kTfLiteBuiltinReluN1To1);
1121 case kTfLiteBuiltinRelu6:
1122 return VisitActivationOperator(delegateData,
1123 tfLiteContext,
1124 tfLiteNode,
1125 nodeIndex,
1126 kTfLiteBuiltinRelu6);
Matthew Sloyanc49aacc2023-04-28 17:27:26 +01001127 case kTfLiteBuiltinReshape:
1128 return VisitReshapeOperator(delegateData,
1129 tfLiteContext,
1130 tfLiteNode,
1131 nodeIndex,
1132 kTfLiteBuiltinReshape);
John Mcloughlin083586d2023-04-28 18:36:52 +01001133 case kTfLiteBuiltinResizeNearestNeighbor:
1134 return VisitResizeOperator(delegateData,
1135 tfLiteContext,
1136 tfLiteNode,
1137 nodeIndex,
1138 kTfLiteBuiltinResizeNearestNeighbor);
1139 case kTfLiteBuiltinResizeBilinear:
1140 return VisitResizeOperator(delegateData,
1141 tfLiteContext,
1142 tfLiteNode,
1143 nodeIndex,
1144 kTfLiteBuiltinResizeBilinear);
Tracy Narine7306bbe2023-07-17 16:06:26 +01001145 case kTfLiteBuiltinReverseV2:
1146 return VisitReverseV2Operator(delegateData,
1147 tfLiteContext,
1148 tfLiteNode,
1149 nodeIndex,
1150 kTfLiteBuiltinReverseV2);
Teresa Charlinf69ae562023-04-27 14:42:23 +01001151 case kTfLiteBuiltinRsqrt:
1152 return VisitElementwiseUnaryOperator(delegateData,
1153 tfLiteContext,
1154 tfLiteNode,
1155 nodeIndex,
1156 kTfLiteBuiltinRsqrt,
1157 armnn::UnaryOperation::Rsqrt);
Kevin May93bbf002024-03-11 09:31:10 +00001158 case kTfLiteBuiltinScatterNd:
1159 return VisitScatterNdOperator(delegateData,
1160 tfLiteContext,
1161 tfLiteNode,
1162 nodeIndex,
1163 kTfLiteBuiltinScatterNd);
John Mcloughlin0422cf22023-04-27 16:55:00 +01001164 case kTfLiteBuiltinShape:
1165 return VisitShapeOperator(delegateData,
1166 tfLiteContext,
1167 tfLiteNode,
1168 nodeIndex,
1169 kTfLiteBuiltinShape);
Teresa Charlinf69ae562023-04-27 14:42:23 +01001170 case kTfLiteBuiltinSin:
1171 return VisitElementwiseUnaryOperator(delegateData,
1172 tfLiteContext,
1173 tfLiteNode,
1174 nodeIndex,
1175 kTfLiteBuiltinSin,
1176 armnn::UnaryOperation::Sin);
Teresa Charlin86b03572023-04-28 13:19:12 +01001177 case kTfLiteBuiltinSlice:
1178 return VisitSliceOperator(delegateData,
1179 tfLiteContext,
1180 tfLiteNode,
1181 nodeIndex,
1182 kTfLiteBuiltinSlice);
Teresa Charlin42362962023-04-28 14:23:33 +01001183 case kTfLiteBuiltinSoftmax:
1184 return VisitSoftmaxOperator(delegateData,
1185 tfLiteContext,
1186 tfLiteNode,
1187 nodeIndex,
1188 kTfLiteBuiltinSoftmax);
Kevin May81b66f32023-04-26 14:55:36 +01001189 case kTfLiteBuiltinSpaceToBatchNd:
1190 return VisitSpaceToBatchNdOperator(delegateData,
1191 tfLiteContext,
1192 tfLiteNode,
1193 nodeIndex,
1194 kTfLiteBuiltinSpaceToBatchNd);
Teresa Charlin42362962023-04-28 14:23:33 +01001195 case kTfLiteBuiltinSpaceToDepth:
1196 return VisitSpaceToDepthOperator(delegateData,
1197 tfLiteContext,
1198 tfLiteNode,
1199 nodeIndex,
1200 kTfLiteBuiltinSpaceToDepth);
David Monahanc833cef2023-05-03 15:53:03 +01001201 case kTfLiteBuiltinSplit:
1202 return VisitSplitOperator(delegateData,
1203 tfLiteContext,
1204 tfLiteNode,
1205 nodeIndex,
1206 kTfLiteBuiltinSplit);
1207 case kTfLiteBuiltinSplitV:
1208 return VisitSplitVOperator(delegateData,
1209 tfLiteContext,
1210 tfLiteNode,
1211 nodeIndex,
1212 kTfLiteBuiltinSplitV);
John Mcloughlin0ec00872023-05-15 17:03:49 +01001213 case kTfLiteBuiltinSquaredDifference:
1214 return VisitElementwiseBinaryOperator(delegateData,
1215 tfLiteContext,
1216 tfLiteNode,
1217 nodeIndex,
1218 kTfLiteBuiltinSquaredDifference);
David Monahan6c53f9f2023-04-27 15:21:19 +01001219 case kTfLiteBuiltinSub:
1220 return VisitElementwiseBinaryOperator(delegateData,
1221 tfLiteContext,
1222 tfLiteNode,
1223 nodeIndex,
1224 kTfLiteBuiltinSub);
Teresa Charlinf69ae562023-04-27 14:42:23 +01001225 case kTfLiteBuiltinSqrt:
1226 return VisitElementwiseUnaryOperator(delegateData,
1227 tfLiteContext,
1228 tfLiteNode,
1229 nodeIndex,
1230 kTfLiteBuiltinSqrt,
1231 armnn::UnaryOperation::Sqrt);
Matthew Sloyan3504e422023-05-03 13:53:02 +01001232 case kTfLiteBuiltinSqueeze:
1233 return VisitSqueezeOperator(delegateData,
1234 tfLiteContext,
1235 tfLiteNode,
1236 nodeIndex,
1237 kTfLiteBuiltinSqueeze);
Teresa Charlin86b03572023-04-28 13:19:12 +01001238 case kTfLiteBuiltinStridedSlice:
1239 return VisitStridedSliceOperator(delegateData,
1240 tfLiteContext,
1241 tfLiteNode,
1242 nodeIndex,
1243 kTfLiteBuiltinStridedSlice);
John Mcloughlin083586d2023-04-28 18:36:52 +01001244 case kTfLiteBuiltinSum:
1245 return VisitReduceOperator(delegateData,
1246 tfLiteContext,
1247 tfLiteNode,
1248 nodeIndex,
1249 kTfLiteBuiltinSum);
Matthew Sloyan0bd4c622023-04-27 11:48:26 +01001250 case kTfLiteBuiltinTanh:
1251 return VisitActivationOperator(delegateData,
1252 tfLiteContext,
1253 tfLiteNode,
1254 nodeIndex,
1255 kTfLiteBuiltinTanh);
Tianle Cheng92ce35c2023-07-25 16:41:00 +01001256 case kTfLiteBuiltinTile:
1257 return VisitTileOperator(delegateData,
1258 tfLiteContext,
1259 tfLiteNode,
1260 nodeIndex,
1261 kTfLiteBuiltinTile);
Teresa Charlin42362962023-04-28 14:23:33 +01001262 case kTfLiteBuiltinTranspose:
1263 return VisitTransposeOperator(delegateData,
Tianle Cheng92ce35c2023-07-25 16:41:00 +01001264 tfLiteContext,
1265 tfLiteNode,
1266 nodeIndex,
1267 kTfLiteBuiltinTranspose);
Francis Murtagh3a9e7ba2023-04-26 15:58:39 +01001268 case kTfLiteBuiltinTransposeConv:
1269 return VisitConvolutionOperator(delegateData,
1270 tfLiteContext,
1271 tfLiteNode,
1272 nodeIndex,
1273 kTfLiteBuiltinTransposeConv);
Matthew Sloyan74be13e2023-05-03 17:34:00 +01001274 case kTfLiteBuiltinUnidirectionalSequenceLstm:
1275 return VisitUnidirectionalSequenceLstmOperator(delegateData,
1276 tfLiteContext,
1277 tfLiteNode,
1278 nodeIndex,
1279 kTfLiteBuiltinUnidirectionalSequenceLstm);
Teresa Charlinecebb0f2023-04-27 21:37:56 +01001280 case kTfLiteBuiltinUnpack:
1281 return VisitUnpackOperator(delegateData,
1282 tfLiteContext,
1283 tfLiteNode,
1284 nodeIndex,
1285 kTfLiteBuiltinUnpack);
Ryan OSheaac9607f2023-04-03 11:33:33 +01001286 default:
1287 return kTfLiteError;
1288 }
1289}
Francis Murtagh3a9e7ba2023-04-26 15:58:39 +01001290} // armnnOpaqueDelegate namespace