blob: 03db4a17f8661f79a8dae00e7448fc6b8cd4157b [file] [log] [blame]
Sadik Armagan3c24f432020-10-19 17:35:30 +01001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include <armnn_delegate.hpp>
Sadik Armagan62483be2020-10-23 17:14:43 +01007
Matthew Sloyanac001ee2021-02-03 10:43:04 +00008#include "Version.hpp"
9
Sadik Armagan62483be2020-10-23 17:14:43 +010010#include "Activation.hpp"
11#include "ArgMinMax.hpp"
12#include "BatchSpace.hpp"
13#include "Comparison.hpp"
14#include "Convolution.hpp"
15#include "Control.hpp"
16#include "ElementwiseBinary.hpp"
17#include "ElementwiseUnary.hpp"
18#include "Fill.hpp"
19#include "FullyConnected.hpp"
20#include "Gather.hpp"
Matthew Sloyanc8eb9552020-11-26 10:54:22 +000021#include "LogicalBinary.hpp"
Sadik Armagan62483be2020-10-23 17:14:43 +010022#include "Lstm.hpp"
23#include "Normalization.hpp"
Matthew Sloyana7a12f52021-05-06 10:05:28 +010024#include "Pack.hpp"
Sadik Armagan62483be2020-10-23 17:14:43 +010025#include "Pad.hpp"
26#include "Pooling.hpp"
James Conroy39825482021-05-27 17:44:50 +010027#include "Prelu.hpp"
Sadik Armagan62483be2020-10-23 17:14:43 +010028#include "Quantization.hpp"
29#include "Redefine.hpp"
Sadik Armagana2747482021-02-09 10:28:54 +000030#include "Reduce.hpp"
Sadik Armagan62483be2020-10-23 17:14:43 +010031#include "Resize.hpp"
32#include "Round.hpp"
Keith Davis0176fd82021-06-01 17:36:32 +010033#include "Shape.hpp"
Sadik Armagan62483be2020-10-23 17:14:43 +010034#include "Slice.hpp"
35#include "Softmax.hpp"
36#include "SpaceDepth.hpp"
Sadik Armagan34fa1bd2020-11-27 12:40:52 +000037#include "Split.hpp"
Sadik Armagan62483be2020-10-23 17:14:43 +010038#include "Transpose.hpp"
Narumol Prangnawarat7684b182021-08-12 14:48:15 +010039#include "UnidirectionalSequenceLstm.hpp"
Kevin May8ab2d7a2021-05-07 09:32:51 +010040#include "Unpack.hpp"
Sadik Armagan62483be2020-10-23 17:14:43 +010041
Colm Donelan3e32a872021-10-04 22:55:37 +010042#include <armnnUtils/Filesystem.hpp>
Jan Eilers17d34da2021-12-08 16:15:12 +000043#include <armnn/utility/Timer.hpp>
Sadik Armagan62483be2020-10-23 17:14:43 +010044#include <flatbuffers/flatbuffers.h>
45#include <tensorflow/lite/context_util.h>
Jim Flynn4b2f3472021-10-13 21:20:07 +010046#include <tensorflow/lite/schema/schema_generated.h>
Sadik Armagan62483be2020-10-23 17:14:43 +010047
Sadik Armagan3c24f432020-10-19 17:35:30 +010048#include <algorithm>
Matthew Sloyanac001ee2021-02-03 10:43:04 +000049#include <iostream>
Sadik Armagan62483be2020-10-23 17:14:43 +010050#include <sstream>
Sadik Armagan3c24f432020-10-19 17:35:30 +010051
52namespace armnnDelegate
53{
54
Sadik Armagan62483be2020-10-23 17:14:43 +010055DelegateOptions TfLiteArmnnDelegateOptionsDefault()
56{
57 DelegateOptions options(armnn::Compute::CpuRef);
58 return options;
59}
60
61TfLiteDelegate* TfLiteArmnnDelegateCreate(armnnDelegate::DelegateOptions options)
62{
63 auto* armnnDelegate = new ::armnnDelegate::Delegate(options);
64 return armnnDelegate->GetDelegate();
65}
66
67void TfLiteArmnnDelegateDelete(TfLiteDelegate* tfLiteDelegate)
68{
69 if (tfLiteDelegate != nullptr)
70 {
71 delete static_cast<::armnnDelegate::Delegate*>(tfLiteDelegate->data_);
72 }
73}
74
75TfLiteStatus DoPrepare(TfLiteContext* tfLiteContext, TfLiteDelegate* tfLiteDelegate)
76{
77 TfLiteIntArray* supportedOperators =
78 static_cast<::armnnDelegate::Delegate*>(tfLiteDelegate->data_)->IdentifyOperatorsToDelegate(tfLiteContext);
79
80 // ArmNN Delegate Registration
81 static const TfLiteRegistration kArmnnSubgraphRegistration = {
82 // ArmnnSubgraph Init
83 .init = [](TfLiteContext* tfLiteContext, const char* buffer, size_t length) -> void* {
Finn Williams6f9f9902020-11-13 13:23:15 +000084 armnn::IgnoreUnused(length);
Sadik Armagan62483be2020-10-23 17:14:43 +010085 const TfLiteDelegateParams* parameters = reinterpret_cast<const TfLiteDelegateParams*>(buffer);
86
87 return static_cast<void*>(ArmnnSubgraph::Create(
88 tfLiteContext, parameters, static_cast<::armnnDelegate::Delegate*>(parameters->delegate->data_)));
89 },
90 // ArmnnSubgraph Free
91 .free = [](TfLiteContext* tfLiteContext, void* buffer) -> void {
Finn Williams6f9f9902020-11-13 13:23:15 +000092 armnn::IgnoreUnused(tfLiteContext);
Sadik Armagan62483be2020-10-23 17:14:43 +010093 if (buffer != nullptr)
94 {
95 delete static_cast<ArmnnSubgraph*>(buffer);
96 }
97 },
98 // ArmnnSubgraph Prepare
99 .prepare = [](TfLiteContext* tfLiteContext, TfLiteNode* tfLiteNode) -> TfLiteStatus {
100 if (tfLiteNode->user_data == nullptr)
101 {
102 return kTfLiteError;
103 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100104 return static_cast<ArmnnSubgraph*>(tfLiteNode->user_data)->Prepare(tfLiteContext);
105 },
106 // ArmnnSubgraph Invoke
107 .invoke = [](TfLiteContext* tfLiteContext, TfLiteNode* tfLiteNode) -> TfLiteStatus {
108 if (tfLiteNode->user_data == nullptr)
109 {
110 return kTfLiteError;
111 }
112
113 return static_cast<ArmnnSubgraph*>(tfLiteNode->user_data)->Invoke(tfLiteContext, tfLiteNode);
114 },
115
116 .profiling_string = nullptr,
117 .builtin_code = kTfLiteBuiltinDelegate,
118 .custom_name = "TfLiteArmNnDelegate",
119 .version = 1,
120 };
121
122 const TfLiteStatus status =
123 tfLiteContext->ReplaceNodeSubsetsWithDelegateKernels(
124 tfLiteContext, kArmnnSubgraphRegistration, supportedOperators, tfLiteDelegate);
125
126 TfLiteIntArrayFree(supportedOperators);
127 return status;
128
129}
130
Sadik Armagan3c24f432020-10-19 17:35:30 +0100131Delegate::Delegate(armnnDelegate::DelegateOptions options)
132 : m_Runtime(nullptr, nullptr),
133 m_Options(std::move(options))
134{
Jan Eilers2cd18472020-12-15 10:42:38 +0000135 // Configures logging for ARMNN
136 if (options.IsLoggingEnabled())
137 {
138 armnn::ConfigureLogging(true, true, options.GetLoggingSeverity());
139 }
140
Sadik Armagan3c24f432020-10-19 17:35:30 +0100141 // Create ArmNN Runtime
Jan Eilersb1c62f12021-10-26 14:56:47 +0100142 m_Runtime = armnn::IRuntime::Create(options.GetRuntimeOptions());
Sadik Armagan3c24f432020-10-19 17:35:30 +0100143
144 std::vector<armnn::BackendId> backends;
Sadik Armagan3c24f432020-10-19 17:35:30 +0100145 if (m_Runtime)
146 {
147 const armnn::BackendIdSet supportedDevices = m_Runtime->GetDeviceSpec().GetSupportedBackends();
148 for (auto& backend : m_Options.GetBackends())
149 {
150 if (std::find(supportedDevices.cbegin(), supportedDevices.cend(), backend) == supportedDevices.cend())
151 {
Sadik Armagan0534e032020-10-27 17:30:18 +0000152 TFLITE_LOG_PROD(tflite::TFLITE_LOG_INFO,
Sadik Armagan3c24f432020-10-19 17:35:30 +0100153 "TfLiteArmnnDelegate: Requested unknown backend %s", backend.Get().c_str());
154 }
155 else
156 {
157 backends.push_back(backend);
158 }
159 }
160 }
161
162 if (backends.empty())
163 {
164 // No known backend specified
165 throw armnn::InvalidArgumentException("TfLiteArmnnDelegate: No known backend specified.");
166 }
167 m_Options.SetBackends(backends);
168
169 TFLITE_LOG_PROD_ONCE(tflite::TFLITE_LOG_INFO, "TfLiteArmnnDelegate: Created TfLite ArmNN delegate.");
170}
171
Sadik Armagan62483be2020-10-23 17:14:43 +0100172TfLiteIntArray* Delegate::IdentifyOperatorsToDelegate(TfLiteContext* tfLiteContext)
Sadik Armagan3c24f432020-10-19 17:35:30 +0100173{
174 TfLiteIntArray* executionPlan = nullptr;
175 if (tfLiteContext->GetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
176 {
177 TF_LITE_KERNEL_LOG(tfLiteContext, "TfLiteArmnnDelegate: Unable to get graph execution plan.");
178 return nullptr;
179 }
180
Sadik Armagan62483be2020-10-23 17:14:43 +0100181 // Delegate data with null network
182 DelegateData delegateData(m_Options.GetBackends());
Sadik Armagan3c24f432020-10-19 17:35:30 +0100183
184 TfLiteIntArray* nodesToDelegate = TfLiteIntArrayCreate(executionPlan->size);
185 nodesToDelegate->size = 0;
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000186
187 std::set<int32_t> unsupportedOperators;
188
Sadik Armagan3c24f432020-10-19 17:35:30 +0100189 for (int i = 0; i < executionPlan->size; ++i)
190 {
191 const int nodeIndex = executionPlan->data[i];
192
193 // If TfLite nodes can be delegated to ArmNN
194 TfLiteNode* tfLiteNode = nullptr;
195 TfLiteRegistration* tfLiteRegistration = nullptr;
196 if (tfLiteContext->GetNodeAndRegistration(
197 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
198 {
199 TF_LITE_KERNEL_LOG(tfLiteContext,
200 "TfLiteArmnnDelegate: Unable to get node and registration for node %d.",
201 nodeIndex);
202 continue;
203 }
204
205 if (ArmnnSubgraph::VisitNode(
Sadik Armagan62483be2020-10-23 17:14:43 +0100206 delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex) != kTfLiteOk)
Sadik Armagan3c24f432020-10-19 17:35:30 +0100207 {
208 // node is not supported by ArmNN
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000209 unsupportedOperators.insert(tfLiteRegistration->builtin_code);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100210 continue;
211 }
212
213 nodesToDelegate->data[nodesToDelegate->size++] = nodeIndex;
214 }
215
Sadik Armaganbfa767c2022-02-09 14:58:03 +0000216 for (std::set<int32_t>::iterator it=unsupportedOperators.begin(); it!=unsupportedOperators.end(); ++it)
217 {
218 TF_LITE_KERNEL_LOG(tfLiteContext,
219 "Operator %s [%d] is not supported by armnn_delegate.",
220 tflite::EnumNameBuiltinOperator(tflite::BuiltinOperator(*it)),
221 *it);
222 }
223
Sadik Armagan62483be2020-10-23 17:14:43 +0100224 std::sort(&nodesToDelegate->data[0], &nodesToDelegate->data[nodesToDelegate->size]);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100225 return nodesToDelegate;
226}
227
228TfLiteDelegate* Delegate::GetDelegate()
229{
230 return &m_Delegate;
231}
232
Matthew Sloyanac001ee2021-02-03 10:43:04 +0000233const std::string Delegate::GetVersion()
234{
235 return DELEGATE_VERSION;
236}
237
Sadik Armagan62483be2020-10-23 17:14:43 +0100238TfLiteStatus ArmnnSubgraph::AddInputLayer(DelegateData& delegateData,
239 TfLiteContext* tfLiteContext,
240 const TfLiteIntArray* inputs,
241 std::vector<armnn::BindingPointInfo>& inputBindings)
242{
Finn Williams6f9f9902020-11-13 13:23:15 +0000243 const size_t numInputs = static_cast<size_t>(inputs->size);
Sadik Armagan62483be2020-10-23 17:14:43 +0100244 for (unsigned int i = 0; i < numInputs; ++i)
245 {
246 const int32_t tensorId = inputs->data[i];
247 const TfLiteTensor tensor = tfLiteContext->tensors[tensorId];
Sadik Armagan6e36a642020-11-10 21:18:41 +0000248 // Do not create bindings for constant inputs
249 if (tensor.allocation_type == kTfLiteMmapRo)
250 {
251 continue;
252 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100253
254 auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
255 armnn::IConnectableLayer* layer = delegateData.m_Network->AddInputLayer(bindingId);
256
257 auto tensorInfo = GetTensorInfoForTfLiteTensor(tensor);
258 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
259 outputSlot.SetTensorInfo(tensorInfo);
260
261 // Store for creating connections
Finn Williams6f9f9902020-11-13 13:23:15 +0000262 delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] = &outputSlot;
Sadik Armagan62483be2020-10-23 17:14:43 +0100263
Sadik Armagan6e36a642020-11-10 21:18:41 +0000264 inputBindings.push_back(std::make_pair(bindingId, tensorInfo));
Sadik Armagan62483be2020-10-23 17:14:43 +0100265 }
Sadik Armagan6e36a642020-11-10 21:18:41 +0000266
Sadik Armagan62483be2020-10-23 17:14:43 +0100267 return kTfLiteOk;
268}
269
270TfLiteStatus ArmnnSubgraph::AddOutputLayer(DelegateData& delegateData,
271 TfLiteContext* tfLiteContext,
272 const TfLiteIntArray* outputs,
273 std::vector<armnn::BindingPointInfo>& outputBindings)
274{
Finn Williams6f9f9902020-11-13 13:23:15 +0000275 const size_t numOutputs = static_cast<size_t>(outputs->size);
Sadik Armagan62483be2020-10-23 17:14:43 +0100276 for (unsigned int i = 0; i < numOutputs; ++i)
277 {
278 const int32_t tensorId = outputs->data[i];
279 const TfLiteTensor tensor = tfLiteContext->tensors[tensorId];
280
281 auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
282 armnn::IConnectableLayer* layer = delegateData.m_Network->AddOutputLayer(bindingId);
283
284 auto tensorInfo = GetTensorInfoForTfLiteTensor(tensor);
Finn Williams6f9f9902020-11-13 13:23:15 +0000285 ARMNN_ASSERT(delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] != nullptr);
286 delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)]->Connect(layer->GetInputSlot(0));
Sadik Armagan62483be2020-10-23 17:14:43 +0100287 outputBindings.push_back(std::make_pair(bindingId, tensorInfo));
288 }
289
290 return kTfLiteOk;
291}
292
Sadik Armagan3c24f432020-10-19 17:35:30 +0100293ArmnnSubgraph* ArmnnSubgraph::Create(TfLiteContext* tfLiteContext,
294 const TfLiteDelegateParams* parameters,
295 const Delegate* delegate)
296{
Jan Eilers17d34da2021-12-08 16:15:12 +0000297 const auto startTime = armnn::GetTimeNow();
298 ARMNN_LOG(info) << "ArmnnSubgraph creation";
299
Sadik Armagan3c24f432020-10-19 17:35:30 +0100300 TfLiteIntArray* executionPlan;
301 if (tfLiteContext->GetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
302 {
303 return nullptr;
304 }
305
Sadik Armagan62483be2020-10-23 17:14:43 +0100306 // Initialize DelegateData holds network and output slots information
307 DelegateData delegateData(delegate->m_Options.GetBackends());
308
309 // Build ArmNN Network
Sadik Armagan3c24f432020-10-19 17:35:30 +0100310 armnn::NetworkOptions networkOptions = {};
311 armnn::NetworkId networkId;
Sadik Armagan62483be2020-10-23 17:14:43 +0100312 delegateData.m_Network = armnn::INetwork::Create(networkOptions);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100313
Sadik Armagan6e36a642020-11-10 21:18:41 +0000314 delegateData.m_OutputSlotForNode = std::vector<armnn::IOutputSlot*>(tfLiteContext->tensors_size, nullptr);
315
Sadik Armagan62483be2020-10-23 17:14:43 +0100316 std::vector<armnn::BindingPointInfo> inputBindings;
317 std::vector<armnn::BindingPointInfo> outputBindings;
318
319 // Add input layer
320 auto status = AddInputLayer(delegateData, tfLiteContext, parameters->input_tensors, inputBindings);
321 if (status != kTfLiteOk)
322 {
323 throw armnn::Exception("TfLiteArmnnDelegate: Unable to add Inputs to the network!");
324 }
325
326 // Parse TfLite delegate nodes to ArmNN
Jan Eilers17d34da2021-12-08 16:15:12 +0000327 const auto parseStartTime = armnn::GetTimeNow();
Sadik Armagan3c24f432020-10-19 17:35:30 +0100328 for (int i = 0; i < parameters->nodes_to_replace->size; ++i)
329 {
330 const int nodeIndex = parameters->nodes_to_replace->data[i];
331
332 TfLiteNode* tfLiteNode = nullptr;
333 TfLiteRegistration* tfLiteRegistration = nullptr;
334 if (tfLiteContext->GetNodeAndRegistration(
335 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
336 {
Finn Williams6f9f9902020-11-13 13:23:15 +0000337 throw armnn::Exception(&"TfLiteArmnnDelegate: Unable to get node registration: " [ nodeIndex]);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100338 }
339
Sadik Armagan62483be2020-10-23 17:14:43 +0100340 if (VisitNode(delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex) != kTfLiteOk)
Sadik Armagan3c24f432020-10-19 17:35:30 +0100341 {
Finn Williams6f9f9902020-11-13 13:23:15 +0000342 throw armnn::Exception(&"TfLiteArmnnDelegate: Unable to parse node: " [ nodeIndex]);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100343 }
344 }
Jan Eilers17d34da2021-12-08 16:15:12 +0000345 ARMNN_LOG(info) << "Parse nodes to ArmNN time: " << std::setprecision(2)
346 << std::fixed << armnn::GetTimeDuration(parseStartTime).count() << " ms";
Sadik Armagan3c24f432020-10-19 17:35:30 +0100347
Sadik Armagan62483be2020-10-23 17:14:43 +0100348 // Add Output layer
349 status = AddOutputLayer(delegateData, tfLiteContext, parameters->output_tensors, outputBindings);
350 if (status != kTfLiteOk)
351 {
352 throw armnn::Exception("TfLiteArmnnDelegate: Unable to add Outputs to the network!");
353 }
354
355 // Optimize ArmNN network
356 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
357 try
358 {
Jan Eilers17d34da2021-12-08 16:15:12 +0000359 const auto optimizeStartTime = armnn::GetTimeNow();
Sadik Armagan6e36a642020-11-10 21:18:41 +0000360 optNet = armnn::Optimize(*(delegateData.m_Network.get()),
Sadik Armagan62483be2020-10-23 17:14:43 +0100361 delegate->m_Options.GetBackends(),
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000362 delegate->m_Runtime->GetDeviceSpec(),
363 delegate->m_Options.GetOptimizerOptions());
Jan Eilers17d34da2021-12-08 16:15:12 +0000364 ARMNN_LOG(info) << "Optimize ArmnnSubgraph time: " << std::setprecision(2)
365 << std::fixed << armnn::GetTimeDuration(optimizeStartTime).count() << " ms";
Sadik Armagan62483be2020-10-23 17:14:43 +0100366 }
367 catch (std::exception &ex)
368 {
369 std::stringstream exMessage;
370 exMessage << "TfLiteArmnnDelegate: Exception (" << ex.what() << ") caught from optimize.";
371 throw armnn::Exception(exMessage.str());
372 }
Sadik Armagan3c24f432020-10-19 17:35:30 +0100373 if (!optNet)
374 {
Sadik Armagan62483be2020-10-23 17:14:43 +0100375 // Optimize failed
Sadik Armagan3c24f432020-10-19 17:35:30 +0100376 throw armnn::Exception("TfLiteArmnnDelegate: Unable to optimize the network!");
377 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100378
Colm Donelan3e32a872021-10-04 22:55:37 +0100379 // If set, we will serialize the optimized model into a dot file.
380 const std::string serializeToDotFile = delegate->m_Options.GetSerializeToDot();
381 if (!serializeToDotFile.empty())
382 {
Jan Eilers17d34da2021-12-08 16:15:12 +0000383 ARMNN_LOG(info) << "Writing graph to dot file: " << serializeToDotFile;
Colm Donelan3e32a872021-10-04 22:55:37 +0100384 fs::path filename = serializeToDotFile;
385 std::fstream file(filename.c_str(), std::ios_base::out);
386 optNet->SerializeToDot(file);
387 }
388
Sadik Armagan62483be2020-10-23 17:14:43 +0100389 try
390 {
Jan Eilers17d34da2021-12-08 16:15:12 +0000391 const auto loadStartTime = armnn::GetTimeNow();
392
Sadik Armagan62483be2020-10-23 17:14:43 +0100393 // Load graph into runtime
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000394 std::string errorMessage;
Narumol Prangnawarat74a3cf52021-01-29 15:38:54 +0000395 armnn::Status loadingStatus;
Colm Donelan3e32a872021-10-04 22:55:37 +0100396 armnn::MemorySource memorySource = armnn::MemorySource::Undefined;
Narumol Prangnawarat74a3cf52021-01-29 15:38:54 +0000397 if (delegate->m_Options.GetOptimizerOptions().m_ImportEnabled)
398 {
Colm Donelan3e32a872021-10-04 22:55:37 +0100399 memorySource = armnn::MemorySource::Malloc;
Narumol Prangnawarat74a3cf52021-01-29 15:38:54 +0000400 }
Colm Donelan3e32a872021-10-04 22:55:37 +0100401 armnn::INetworkProperties networkProperties(false,
402 memorySource,
403 memorySource,
404 delegate->m_Options.GetInternalProfilingState(),
405 delegate->m_Options.GetInternalProfilingDetail());
406 loadingStatus = delegate->m_Runtime->LoadNetwork(networkId,
407 std::move(optNet),
408 errorMessage,
409 networkProperties);
Sadik Armagan62483be2020-10-23 17:14:43 +0100410 if (loadingStatus != armnn::Status::Success)
411 {
Colm Donelan45142282021-10-21 23:39:52 +0100412 // Network load failed.
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000413 throw armnn::Exception("TfLiteArmnnDelegate: Network could not be loaded:" + errorMessage);
Sadik Armagan62483be2020-10-23 17:14:43 +0100414 }
Jan Eilers17d34da2021-12-08 16:15:12 +0000415
416 ARMNN_LOG(info) << "Load ArmnnSubgraph time: " << std::setprecision(2)
417 << std::fixed << armnn::GetTimeDuration(loadStartTime).count() << " ms";
Sadik Armagan62483be2020-10-23 17:14:43 +0100418 }
419 catch (std::exception& ex)
420 {
421 std::stringstream exMessage;
422 exMessage << "TfLiteArmnnDelegate: Exception (" << ex.what() << ") caught from LoadNetwork.";
423 throw armnn::Exception(exMessage.str());
424 }
Sadik Armagan3c24f432020-10-19 17:35:30 +0100425
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000426 // Register debug callback function
427 if (delegate->m_Options.GetDebugCallbackFunction().has_value())
428 {
429 delegate->m_Runtime->RegisterDebugCallback(networkId, delegate->m_Options.GetDebugCallbackFunction().value());
430 }
431
Jan Eilers17d34da2021-12-08 16:15:12 +0000432 ARMNN_LOG(info) << "Overall ArmnnSubgraph creation time: " << std::setprecision(2)
433 << std::fixed << armnn::GetTimeDuration(startTime).count() << " ms\n";
434
Sadik Armagan3c24f432020-10-19 17:35:30 +0100435 // Create a new SubGraph with networkId and runtime
Sadik Armagan62483be2020-10-23 17:14:43 +0100436 return new ArmnnSubgraph(networkId, delegate->m_Runtime.get(), inputBindings, outputBindings);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100437}
438
439TfLiteStatus ArmnnSubgraph::Prepare(TfLiteContext* tfLiteContext)
440{
Finn Williams6f9f9902020-11-13 13:23:15 +0000441 armnn::IgnoreUnused(tfLiteContext);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100442 return kTfLiteOk;
443}
444
Sadik Armagan62483be2020-10-23 17:14:43 +0100445TfLiteStatus ArmnnSubgraph::Invoke(TfLiteContext* tfLiteContext, TfLiteNode* tfLiteNode)
Sadik Armagan3c24f432020-10-19 17:35:30 +0100446{
Sadik Armagan62483be2020-10-23 17:14:43 +0100447 // Prepare inputs
448 armnn::InputTensors inputTensors;
449 size_t inputIndex = 0;
450 for (auto inputIdx : tflite::TfLiteIntArrayView(tfLiteNode->inputs))
451 {
452 TfLiteTensor* tensor = &tfLiteContext->tensors[inputIdx];
453 if (tensor->allocation_type != kTfLiteMmapRo)
454 {
455 const armnn::BindingPointInfo& inputBinding = m_InputBindings[inputIndex];
Cathal Corbett5b8093c2021-10-22 11:12:07 +0100456 armnn::TensorInfo inputTensorInfo = inputBinding.second;
457 inputTensorInfo.SetConstant(true);
458 const armnn::ConstTensor inputTensor(inputTensorInfo, tensor->data.data);
Sadik Armagan62483be2020-10-23 17:14:43 +0100459 inputTensors.emplace_back(inputIdx, inputTensor);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100460
Sadik Armagan62483be2020-10-23 17:14:43 +0100461 ++inputIndex;
462 }
463 }
464
465 // Prepare outputs
466 armnn::OutputTensors outputTensors;
467 size_t outputIndex = 0;
468 for (auto outputIdx : tflite::TfLiteIntArrayView(tfLiteNode->outputs))
469 {
470 const armnn::BindingPointInfo& outputBinding = m_OutputBindings[outputIndex];
471 TfLiteTensor* tensor = &tfLiteContext->tensors[outputIdx];
472 const armnn::Tensor outputTensor(outputBinding.second, tensor->data.data);
473 outputTensors.emplace_back(outputIdx, outputTensor);
474
475 ++outputIndex;
476 }
477
478 // Run graph
479 auto status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Colm Donelan45142282021-10-21 23:39:52 +0100480 // The delegate holds its own Arm NN runtime so this is our last chance to print internal profiling data.
481 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
482 if (profiler && profiler->IsProfilingEnabled())
483 {
484 profiler->Print(std::cout);
485 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100486 return (status == armnn::Status::Success) ? kTfLiteOk : kTfLiteError;
Sadik Armagan3c24f432020-10-19 17:35:30 +0100487}
488
Sadik Armagan62483be2020-10-23 17:14:43 +0100489TfLiteStatus ArmnnSubgraph::VisitNode(DelegateData& delegateData,
Sadik Armagan3c24f432020-10-19 17:35:30 +0100490 TfLiteContext* tfLiteContext,
491 TfLiteRegistration* tfLiteRegistration,
492 TfLiteNode* tfLiteNode,
493 int nodeIndex)
494{
Sadik Armagan62483be2020-10-23 17:14:43 +0100495 switch (tfLiteRegistration->builtin_code)
496 {
497 case kTfLiteBuiltinAbs:
498 return VisitElementwiseUnaryOperator(delegateData,
499 tfLiteContext,
500 tfLiteNode,
501 nodeIndex,
502 armnn::UnaryOperation::Abs);
503 case kTfLiteBuiltinAdd:
504 return VisitElementwiseBinaryOperator(delegateData,
505 tfLiteContext,
506 tfLiteNode,
507 nodeIndex,
508 kTfLiteBuiltinAdd);
509 case kTfLiteBuiltinArgMax:
510 return VisitArgMinMaxOperator(delegateData,
511 tfLiteContext,
512 tfLiteNode,
513 nodeIndex,
514 kTfLiteBuiltinArgMax);
515 case kTfLiteBuiltinArgMin:
516 return VisitArgMinMaxOperator(delegateData,
517 tfLiteContext,
518 tfLiteNode,
519 nodeIndex,
520 kTfLiteBuiltinArgMin);
521 case kTfLiteBuiltinAveragePool2d:
522 return VisitPoolingOperator(delegateData,
523 tfLiteContext,
524 tfLiteNode,
525 nodeIndex,
526 kTfLiteBuiltinAveragePool2d);
527 case kTfLiteBuiltinBatchToSpaceNd:
528 return VisitBatchToSpaceNdOperator(delegateData,
529 tfLiteContext,
530 tfLiteNode,
531 nodeIndex,
532 kTfLiteBuiltinBatchToSpaceNd);
Sadik Armagan937565b2021-04-21 14:03:28 +0100533 case kTfLiteBuiltinCast:
534 return VisitCastOperator(delegateData,
535 tfLiteContext,
536 tfLiteNode,
537 nodeIndex,
538 kTfLiteBuiltinCast);
Sadik Armagan62483be2020-10-23 17:14:43 +0100539 case kTfLiteBuiltinConcatenation:
540 return VisitControlOperator(delegateData,
541 tfLiteContext,
542 tfLiteNode,
543 nodeIndex,
544 kTfLiteBuiltinConcatenation);
545 case kTfLiteBuiltinConv2d:
546 return VisitConvolutionOperator(delegateData,
547 tfLiteContext,
548 tfLiteNode,
549 nodeIndex,
550 kTfLiteBuiltinConv2d);
Matthew Sloyan81ec9942021-10-12 10:26:30 +0100551// Conv3d is only correctly supported for external delegates from TF Lite v2.6, as there was a breaking bug in v2.5.
552#if defined(ARMNN_POST_TFLITE_2_5)
553 case kTfLiteBuiltinConv3d:
554 return VisitConvolutionOperator(delegateData,
555 tfLiteContext,
556 tfLiteNode,
557 nodeIndex,
558 kTfLiteBuiltinConv3d);
559#endif
Sadik Armagan62483be2020-10-23 17:14:43 +0100560 case kTfLiteBuiltinDepthToSpace:
561 return VisitDepthToSpaceOperator(delegateData,
562 tfLiteContext,
563 tfLiteNode,
564 nodeIndex,
565 kTfLiteBuiltinDepthToSpace);
566 case kTfLiteBuiltinDepthwiseConv2d:
567 return VisitConvolutionOperator(delegateData,
568 tfLiteContext,
569 tfLiteNode,
570 nodeIndex,
571 kTfLiteBuiltinDepthwiseConv2d);
572 case kTfLiteBuiltinDequantize:
573 return VisitDequantizeOperator(delegateData,
574 tfLiteContext,
575 tfLiteNode,
576 nodeIndex,
577 kTfLiteBuiltinDequantize);
578 case kTfLiteBuiltinDiv:
579 return VisitElementwiseBinaryOperator(delegateData,
580 tfLiteContext,
581 tfLiteNode,
582 nodeIndex,
583 kTfLiteBuiltinDiv);
584 case kTfLiteBuiltinElu:
585 return VisitActivationOperator(delegateData,
586 tfLiteContext,
587 tfLiteNode,
588 nodeIndex,
589 kTfLiteBuiltinElu);
590 case kTfLiteBuiltinEqual:
591 return VisitComparisonOperator(delegateData,
592 tfLiteContext,
593 tfLiteNode,
594 nodeIndex,
595 kTfLiteBuiltinEqual);
596 case kTfLiteBuiltinExp:
597 return VisitElementwiseUnaryOperator(delegateData,
598 tfLiteContext,
599 tfLiteNode,
600 nodeIndex,
601 armnn::UnaryOperation::Exp);
602 case kTfLiteBuiltinExpandDims:
603 return VisitExpandDimsOperator(delegateData,
604 tfLiteContext,
605 tfLiteNode,
606 nodeIndex,
607 kTfLiteBuiltinExpandDims);
608 case kTfLiteBuiltinFill:
609 return VisitFillOperator(delegateData,
610 tfLiteContext,
611 tfLiteNode,
612 nodeIndex,
613 kTfLiteBuiltinFill);
614 case kTfLiteBuiltinFloor:
615 return VisitFloorOperator(delegateData,
616 tfLiteContext,
617 tfLiteNode,
618 nodeIndex,
619 kTfLiteBuiltinFloor);
Jim Flynn4b2f3472021-10-13 21:20:07 +0100620 case kTfLiteBuiltinFloorDiv:
621 return VisitElementwiseBinaryOperator(delegateData,
622 tfLiteContext,
623 tfLiteNode,
624 nodeIndex,
625 kTfLiteBuiltinFloorDiv);
Sadik Armagan62483be2020-10-23 17:14:43 +0100626 case kTfLiteBuiltinFullyConnected:
627 return VisitFullyConnectedOperator(delegateData,
628 tfLiteContext,
629 tfLiteNode,
630 nodeIndex,
631 kTfLiteBuiltinFullyConnected);
632 case kTfLiteBuiltinGather:
633 return VisitGatherOperator(delegateData,
634 tfLiteContext,
635 tfLiteNode,
636 nodeIndex,
637 kTfLiteBuiltinGather);
Sadik Armagan62483be2020-10-23 17:14:43 +0100638 case kTfLiteBuiltinGreater:
639 return VisitComparisonOperator(delegateData,
640 tfLiteContext,
641 tfLiteNode,
642 nodeIndex,
643 kTfLiteBuiltinGreater);
644 case kTfLiteBuiltinGreaterEqual:
645 return VisitComparisonOperator(delegateData,
646 tfLiteContext,
647 tfLiteNode,
648 nodeIndex,
649 kTfLiteBuiltinGreaterEqual);
650 case kTfLiteBuiltinHardSwish:
651 return VisitActivationOperator(delegateData,
652 tfLiteContext,
653 tfLiteNode,
654 nodeIndex,
655 kTfLiteBuiltinHardSwish);
656 case kTfLiteBuiltinL2Normalization:
Sadik Armagan4b227bb2021-01-22 10:53:38 +0000657 return VisitL2NormalizationOperator(delegateData,
658 tfLiteContext,
659 tfLiteNode,
660 nodeIndex,
661 kTfLiteBuiltinL2Normalization);
Sadik Armagan62483be2020-10-23 17:14:43 +0100662 case kTfLiteBuiltinL2Pool2d:
663 return VisitPoolingOperator(delegateData,
664 tfLiteContext,
665 tfLiteNode,
666 nodeIndex,
667 kTfLiteBuiltinL2Pool2d);
668 case kTfLiteBuiltinLess:
669 return VisitComparisonOperator(delegateData,
670 tfLiteContext,
671 tfLiteNode,
672 nodeIndex,
673 kTfLiteBuiltinLess);
674 case kTfLiteBuiltinLessEqual:
675 return VisitComparisonOperator(delegateData,
676 tfLiteContext,
677 tfLiteNode,
678 nodeIndex,
679 kTfLiteBuiltinLessEqual);
680 case kTfLiteBuiltinLocalResponseNormalization:
Sadik Armagan4b227bb2021-01-22 10:53:38 +0000681 return VisitLocalResponseNormalizationOperator(delegateData,
682 tfLiteContext,
683 tfLiteNode,
684 nodeIndex,
685 kTfLiteBuiltinLocalResponseNormalization);
Matthew Sloyanc8eb9552020-11-26 10:54:22 +0000686 case kTfLiteBuiltinLogicalAnd:
687 return VisitLogicalBinaryOperator(delegateData,
688 tfLiteContext,
689 tfLiteNode,
690 nodeIndex,
691 kTfLiteBuiltinLogicalAnd,
692 armnn::LogicalBinaryOperation::LogicalAnd);
693 case kTfLiteBuiltinLogicalNot:
694 return VisitElementwiseUnaryOperator(delegateData,
695 tfLiteContext,
696 tfLiteNode,
697 nodeIndex,
698 armnn::UnaryOperation::LogicalNot);
699 case kTfLiteBuiltinLogicalOr:
700 return VisitLogicalBinaryOperator(delegateData,
701 tfLiteContext,
702 tfLiteNode,
703 nodeIndex,
704 kTfLiteBuiltinLogicalOr,
705 armnn::LogicalBinaryOperation::LogicalOr);
Sadik Armagan62483be2020-10-23 17:14:43 +0100706 case kTfLiteBuiltinLogistic:
707 return VisitActivationOperator(delegateData,
708 tfLiteContext,
709 tfLiteNode,
710 nodeIndex,
711 kTfLiteBuiltinLogistic);
712 case kTfLiteBuiltinLogSoftmax:
713 return VisitSoftmaxOperator(delegateData,
714 tfLiteContext,
715 tfLiteNode,
716 nodeIndex,
717 kTfLiteBuiltinLogSoftmax);
718 case kTfLiteBuiltinLstm:
719 return VisitLstmOperator(delegateData,
720 tfLiteContext,
721 tfLiteNode,
722 nodeIndex,
723 kTfLiteBuiltinLstm);
724 case kTfLiteBuiltinMaxPool2d:
725 return VisitPoolingOperator(delegateData,
726 tfLiteContext,
727 tfLiteNode,
728 nodeIndex,
729 kTfLiteBuiltinMaxPool2d);
730 case kTfLiteBuiltinMaximum:
731 return VisitElementwiseBinaryOperator(delegateData,
732 tfLiteContext,
733 tfLiteNode,
734 nodeIndex,
735 kTfLiteBuiltinMaximum);
736 case kTfLiteBuiltinMean:
737 return VisitControlOperator(delegateData,
738 tfLiteContext,
739 tfLiteNode,
740 nodeIndex,
741 kTfLiteBuiltinMean);
742 case kTfLiteBuiltinMinimum:
743 return VisitElementwiseBinaryOperator(delegateData,
744 tfLiteContext,
745 tfLiteNode,
746 nodeIndex,
747 kTfLiteBuiltinMinimum);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +0100748 case kTfLiteBuiltinMirrorPad:
749 return VisitPadOperator(delegateData,
750 tfLiteContext,
751 tfLiteNode,
752 nodeIndex,
753 kTfLiteBuiltinMirrorPad);
Sadik Armagan62483be2020-10-23 17:14:43 +0100754 case kTfLiteBuiltinMul:
755 return VisitElementwiseBinaryOperator(delegateData,
756 tfLiteContext,
757 tfLiteNode,
758 nodeIndex,
759 kTfLiteBuiltinMul);
760 case kTfLiteBuiltinNeg:
761 return VisitElementwiseUnaryOperator(delegateData,
762 tfLiteContext,
763 tfLiteNode,
764 nodeIndex,
765 armnn::UnaryOperation::Neg);
766 case kTfLiteBuiltinNotEqual:
767 return VisitComparisonOperator(delegateData,
768 tfLiteContext,
769 tfLiteNode,
770 nodeIndex,
771 kTfLiteBuiltinNotEqual);
Matthew Sloyana7a12f52021-05-06 10:05:28 +0100772 case kTfLiteBuiltinPack:
773 return VisitPackOperator(delegateData,
774 tfLiteContext,
775 tfLiteNode,
776 nodeIndex,
777 kTfLiteBuiltinPack);
Sadik Armagan62483be2020-10-23 17:14:43 +0100778 case kTfLiteBuiltinPad:
779 return VisitPadOperator(delegateData,
780 tfLiteContext,
781 tfLiteNode,
782 nodeIndex,
783 kTfLiteBuiltinPad);
784 case kTfLiteBuiltinPadv2:
785 return VisitPadOperator(delegateData,
786 tfLiteContext,
787 tfLiteNode,
788 nodeIndex,
789 kTfLiteBuiltinPadv2);
790 case kTfLiteBuiltinPrelu:
James Conroy39825482021-05-27 17:44:50 +0100791 return VisitPreluOperator(delegateData,
792 tfLiteContext,
793 tfLiteNode,
794 nodeIndex,
795 kTfLiteBuiltinPrelu);
Sadik Armagan62483be2020-10-23 17:14:43 +0100796 case kTfLiteBuiltinQuantize:
797 return VisitQuantizeOperator(delegateData,
798 tfLiteContext,
799 tfLiteNode,
800 nodeIndex,
801 kTfLiteBuiltinQuantize);
802 case kTfLiteBuiltinRank:
803 return VisitControlOperator(delegateData,
804 tfLiteContext,
805 tfLiteNode,
806 nodeIndex,
807 kTfLiteBuiltinRank);
Sadik Armagana2747482021-02-09 10:28:54 +0000808 case kTfLiteBuiltinReduceMax:
809 return VisitReduceOperator(delegateData,
810 tfLiteContext,
811 tfLiteNode,
812 nodeIndex,
813 kTfLiteBuiltinReduceMax);
814 case kTfLiteBuiltinReduceMin:
815 return VisitReduceOperator(delegateData,
816 tfLiteContext,
817 tfLiteNode,
818 nodeIndex,
819 kTfLiteBuiltinReduceMin);
Teresa Charlin4e3e8312021-08-05 12:34:37 +0100820 case kTfLiteBuiltinReduceProd:
821 return VisitReduceOperator(delegateData,
822 tfLiteContext,
823 tfLiteNode,
824 nodeIndex,
825 kTfLiteBuiltinReduceProd);
Sadik Armagan62483be2020-10-23 17:14:43 +0100826 case kTfLiteBuiltinRelu:
827 return VisitActivationOperator(delegateData,
828 tfLiteContext,
829 tfLiteNode,
830 nodeIndex,
831 kTfLiteBuiltinRelu);
832 case kTfLiteBuiltinReluN1To1:
833 return VisitActivationOperator(delegateData,
834 tfLiteContext,
835 tfLiteNode,
836 nodeIndex,
837 kTfLiteBuiltinReluN1To1);
838 case kTfLiteBuiltinRelu6:
839 return VisitActivationOperator(delegateData,
840 tfLiteContext,
841 tfLiteNode,
842 nodeIndex,
843 kTfLiteBuiltinRelu6);
844 case kTfLiteBuiltinReshape:
845 return VisitReshapeOperator(delegateData,
846 tfLiteContext,
847 tfLiteNode,
848 nodeIndex,
849 kTfLiteBuiltinReshape);
850 case kTfLiteBuiltinResizeBilinear:
851 return VisitResizeOperator(delegateData,
852 tfLiteContext,
853 tfLiteNode,
854 nodeIndex,
855 kTfLiteBuiltinResizeBilinear);
856 case kTfLiteBuiltinResizeNearestNeighbor:
857 return VisitResizeOperator(delegateData,
858 tfLiteContext,
859 tfLiteNode,
860 nodeIndex,
861 kTfLiteBuiltinResizeNearestNeighbor);
862 case kTfLiteBuiltinRsqrt:
863 return VisitElementwiseUnaryOperator(delegateData,
864 tfLiteContext,
865 tfLiteNode,
866 nodeIndex,
867 armnn::UnaryOperation::Rsqrt);
Keith Davis0176fd82021-06-01 17:36:32 +0100868 case kTfLiteBuiltinShape:
869 return VisitShapeOperator(delegateData,
870 tfLiteContext,
871 tfLiteNode,
872 nodeIndex,
873 kTfLiteBuiltinShape);
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000874 case kTfLiteBuiltinSplit:
875 return VisitSplitOperator(delegateData,
876 tfLiteContext,
877 tfLiteNode,
878 nodeIndex,
879 kTfLiteBuiltinSplit);
880 case kTfLiteBuiltinSplitV:
881 return VisitSplitVOperator(delegateData,
882 tfLiteContext,
883 tfLiteNode,
884 nodeIndex,
885 kTfLiteBuiltinSplitV);
Sadik Armagan62483be2020-10-23 17:14:43 +0100886 case kTfLiteBuiltinSqrt:
887 return VisitElementwiseUnaryOperator(delegateData,
888 tfLiteContext,
889 tfLiteNode,
890 nodeIndex,
891 armnn::UnaryOperation::Sqrt);
892 case kTfLiteBuiltinSqueeze:
893 return VisitSqueezeOperator(delegateData,
894 tfLiteContext,
895 tfLiteNode,
896 nodeIndex,
897 kTfLiteBuiltinSqueeze);
898 case kTfLiteBuiltinStridedSlice:
899 return VisitSliceOperator(delegateData,
900 tfLiteContext,
901 tfLiteNode,
902 nodeIndex,
903 kTfLiteBuiltinStridedSlice);
Sadik Armagana2747482021-02-09 10:28:54 +0000904 case kTfLiteBuiltinSum:
905 return VisitReduceOperator(delegateData,
906 tfLiteContext,
907 tfLiteNode,
908 nodeIndex,
909 kTfLiteBuiltinSum);
Sadik Armagan62483be2020-10-23 17:14:43 +0100910 case kTfLiteBuiltinTranspose:
911 return VisitTransposeOperator(delegateData,
912 tfLiteContext,
913 tfLiteNode,
914 nodeIndex,
915 kTfLiteBuiltinTranspose);
916 case kTfLiteBuiltinTransposeConv:
917 return VisitConvolutionOperator(delegateData,
918 tfLiteContext,
919 tfLiteNode,
920 nodeIndex,
921 kTfLiteBuiltinTransposeConv);
922 case kTfLiteBuiltinSoftmax:
923 return VisitSoftmaxOperator(delegateData,
924 tfLiteContext,
925 tfLiteNode,
926 nodeIndex,
927 kTfLiteBuiltinSoftmax);
928 case kTfLiteBuiltinSpaceToBatchNd:
929 return VisitSpaceToBatchNdOperator(delegateData,
930 tfLiteContext,
931 tfLiteNode,
932 nodeIndex,
933 kTfLiteBuiltinSpaceToBatchNd);
934 case kTfLiteBuiltinSpaceToDepth:
935 return VisitSpaceToDepthOperator(delegateData,
936 tfLiteContext,
937 tfLiteNode,
938 nodeIndex,
939 kTfLiteBuiltinSpaceToDepth);
940 case kTfLiteBuiltinSub:
941 return VisitElementwiseBinaryOperator(delegateData,
942 tfLiteContext,
943 tfLiteNode,
944 nodeIndex,
945 kTfLiteBuiltinSub);
946 case kTfLiteBuiltinTanh:
947 return VisitActivationOperator(delegateData,
948 tfLiteContext,
949 tfLiteNode,
950 nodeIndex,
951 kTfLiteBuiltinTanh);
Narumol Prangnawarat7684b182021-08-12 14:48:15 +0100952 case kTfLiteBuiltinUnidirectionalSequenceLstm:
953 return VisitUnidirectionalSequenceLstmOperator(delegateData,
954 tfLiteContext,
955 tfLiteNode,
956 nodeIndex,
957 kTfLiteBuiltinUnidirectionalSequenceLstm);
Kevin May8ab2d7a2021-05-07 09:32:51 +0100958 case kTfLiteBuiltinUnpack:
959 return VisitUnpackOperator(delegateData,
960 tfLiteContext,
961 tfLiteNode,
962 nodeIndex,
963 kTfLiteBuiltinUnpack);
Sadik Armagan62483be2020-10-23 17:14:43 +0100964 default:
965 return kTfLiteError;
966 }
Sadik Armagan3c24f432020-10-19 17:35:30 +0100967}
968
969} // armnnDelegate namespace