blob: 966d17ca98bbe5ab87c1e2377b15d7d36bf85c08 [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>
Sadik Armagan62483be2020-10-23 17:14:43 +010043#include <flatbuffers/flatbuffers.h>
44#include <tensorflow/lite/context_util.h>
45
Sadik Armagan3c24f432020-10-19 17:35:30 +010046#include <algorithm>
Matthew Sloyanac001ee2021-02-03 10:43:04 +000047#include <iostream>
Sadik Armagan62483be2020-10-23 17:14:43 +010048#include <sstream>
Sadik Armagan3c24f432020-10-19 17:35:30 +010049
50namespace armnnDelegate
51{
52
Sadik Armagan62483be2020-10-23 17:14:43 +010053DelegateOptions TfLiteArmnnDelegateOptionsDefault()
54{
55 DelegateOptions options(armnn::Compute::CpuRef);
56 return options;
57}
58
59TfLiteDelegate* TfLiteArmnnDelegateCreate(armnnDelegate::DelegateOptions options)
60{
61 auto* armnnDelegate = new ::armnnDelegate::Delegate(options);
62 return armnnDelegate->GetDelegate();
63}
64
65void TfLiteArmnnDelegateDelete(TfLiteDelegate* tfLiteDelegate)
66{
67 if (tfLiteDelegate != nullptr)
68 {
69 delete static_cast<::armnnDelegate::Delegate*>(tfLiteDelegate->data_);
70 }
71}
72
73TfLiteStatus DoPrepare(TfLiteContext* tfLiteContext, TfLiteDelegate* tfLiteDelegate)
74{
75 TfLiteIntArray* supportedOperators =
76 static_cast<::armnnDelegate::Delegate*>(tfLiteDelegate->data_)->IdentifyOperatorsToDelegate(tfLiteContext);
77
78 // ArmNN Delegate Registration
79 static const TfLiteRegistration kArmnnSubgraphRegistration = {
80 // ArmnnSubgraph Init
81 .init = [](TfLiteContext* tfLiteContext, const char* buffer, size_t length) -> void* {
Finn Williams6f9f9902020-11-13 13:23:15 +000082 armnn::IgnoreUnused(length);
Sadik Armagan62483be2020-10-23 17:14:43 +010083 const TfLiteDelegateParams* parameters = reinterpret_cast<const TfLiteDelegateParams*>(buffer);
84
85 return static_cast<void*>(ArmnnSubgraph::Create(
86 tfLiteContext, parameters, static_cast<::armnnDelegate::Delegate*>(parameters->delegate->data_)));
87 },
88 // ArmnnSubgraph Free
89 .free = [](TfLiteContext* tfLiteContext, void* buffer) -> void {
Finn Williams6f9f9902020-11-13 13:23:15 +000090 armnn::IgnoreUnused(tfLiteContext);
Sadik Armagan62483be2020-10-23 17:14:43 +010091 if (buffer != nullptr)
92 {
93 delete static_cast<ArmnnSubgraph*>(buffer);
94 }
95 },
96 // ArmnnSubgraph Prepare
97 .prepare = [](TfLiteContext* tfLiteContext, TfLiteNode* tfLiteNode) -> TfLiteStatus {
98 if (tfLiteNode->user_data == nullptr)
99 {
100 return kTfLiteError;
101 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100102 return static_cast<ArmnnSubgraph*>(tfLiteNode->user_data)->Prepare(tfLiteContext);
103 },
104 // ArmnnSubgraph Invoke
105 .invoke = [](TfLiteContext* tfLiteContext, TfLiteNode* tfLiteNode) -> TfLiteStatus {
106 if (tfLiteNode->user_data == nullptr)
107 {
108 return kTfLiteError;
109 }
110
111 return static_cast<ArmnnSubgraph*>(tfLiteNode->user_data)->Invoke(tfLiteContext, tfLiteNode);
112 },
113
114 .profiling_string = nullptr,
115 .builtin_code = kTfLiteBuiltinDelegate,
116 .custom_name = "TfLiteArmNnDelegate",
117 .version = 1,
118 };
119
120 const TfLiteStatus status =
121 tfLiteContext->ReplaceNodeSubsetsWithDelegateKernels(
122 tfLiteContext, kArmnnSubgraphRegistration, supportedOperators, tfLiteDelegate);
123
124 TfLiteIntArrayFree(supportedOperators);
125 return status;
126
127}
128
Sadik Armagan3c24f432020-10-19 17:35:30 +0100129Delegate::Delegate(armnnDelegate::DelegateOptions options)
130 : m_Runtime(nullptr, nullptr),
131 m_Options(std::move(options))
132{
Jan Eilers2cd18472020-12-15 10:42:38 +0000133 // Configures logging for ARMNN
134 if (options.IsLoggingEnabled())
135 {
136 armnn::ConfigureLogging(true, true, options.GetLoggingSeverity());
137 }
138
Sadik Armagan3c24f432020-10-19 17:35:30 +0100139 // Create ArmNN Runtime
Jan Eilersb1c62f12021-10-26 14:56:47 +0100140 m_Runtime = armnn::IRuntime::Create(options.GetRuntimeOptions());
Sadik Armagan3c24f432020-10-19 17:35:30 +0100141
142 std::vector<armnn::BackendId> backends;
Sadik Armagan3c24f432020-10-19 17:35:30 +0100143 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 {
Sadik Armagan0534e032020-10-27 17:30:18 +0000150 TFLITE_LOG_PROD(tflite::TFLITE_LOG_INFO,
Sadik Armagan3c24f432020-10-19 17:35:30 +0100151 "TfLiteArmnnDelegate: Requested unknown backend %s", backend.Get().c_str());
152 }
153 else
154 {
155 backends.push_back(backend);
156 }
157 }
158 }
159
160 if (backends.empty())
161 {
162 // No known backend specified
163 throw armnn::InvalidArgumentException("TfLiteArmnnDelegate: No known backend specified.");
164 }
165 m_Options.SetBackends(backends);
166
167 TFLITE_LOG_PROD_ONCE(tflite::TFLITE_LOG_INFO, "TfLiteArmnnDelegate: Created TfLite ArmNN delegate.");
168}
169
Sadik Armagan62483be2020-10-23 17:14:43 +0100170TfLiteIntArray* Delegate::IdentifyOperatorsToDelegate(TfLiteContext* tfLiteContext)
Sadik Armagan3c24f432020-10-19 17:35:30 +0100171{
172 TfLiteIntArray* executionPlan = nullptr;
173 if (tfLiteContext->GetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
174 {
175 TF_LITE_KERNEL_LOG(tfLiteContext, "TfLiteArmnnDelegate: Unable to get graph execution plan.");
176 return nullptr;
177 }
178
Sadik Armagan62483be2020-10-23 17:14:43 +0100179 // Delegate data with null network
180 DelegateData delegateData(m_Options.GetBackends());
Sadik Armagan3c24f432020-10-19 17:35:30 +0100181
182 TfLiteIntArray* nodesToDelegate = TfLiteIntArrayCreate(executionPlan->size);
183 nodesToDelegate->size = 0;
184 for (int i = 0; i < executionPlan->size; ++i)
185 {
186 const int nodeIndex = executionPlan->data[i];
187
188 // If TfLite nodes can be delegated to ArmNN
189 TfLiteNode* tfLiteNode = nullptr;
190 TfLiteRegistration* tfLiteRegistration = nullptr;
191 if (tfLiteContext->GetNodeAndRegistration(
192 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
193 {
194 TF_LITE_KERNEL_LOG(tfLiteContext,
195 "TfLiteArmnnDelegate: Unable to get node and registration for node %d.",
196 nodeIndex);
197 continue;
198 }
199
200 if (ArmnnSubgraph::VisitNode(
Sadik Armagan62483be2020-10-23 17:14:43 +0100201 delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex) != kTfLiteOk)
Sadik Armagan3c24f432020-10-19 17:35:30 +0100202 {
203 // node is not supported by ArmNN
204 continue;
205 }
206
207 nodesToDelegate->data[nodesToDelegate->size++] = nodeIndex;
208 }
209
Sadik Armagan62483be2020-10-23 17:14:43 +0100210 std::sort(&nodesToDelegate->data[0], &nodesToDelegate->data[nodesToDelegate->size]);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100211 return nodesToDelegate;
212}
213
214TfLiteDelegate* Delegate::GetDelegate()
215{
216 return &m_Delegate;
217}
218
Matthew Sloyanac001ee2021-02-03 10:43:04 +0000219const std::string Delegate::GetVersion()
220{
221 return DELEGATE_VERSION;
222}
223
Sadik Armagan62483be2020-10-23 17:14:43 +0100224TfLiteStatus ArmnnSubgraph::AddInputLayer(DelegateData& delegateData,
225 TfLiteContext* tfLiteContext,
226 const TfLiteIntArray* inputs,
227 std::vector<armnn::BindingPointInfo>& inputBindings)
228{
Finn Williams6f9f9902020-11-13 13:23:15 +0000229 const size_t numInputs = static_cast<size_t>(inputs->size);
Sadik Armagan62483be2020-10-23 17:14:43 +0100230 for (unsigned int i = 0; i < numInputs; ++i)
231 {
232 const int32_t tensorId = inputs->data[i];
233 const TfLiteTensor tensor = tfLiteContext->tensors[tensorId];
Sadik Armagan6e36a642020-11-10 21:18:41 +0000234 // Do not create bindings for constant inputs
235 if (tensor.allocation_type == kTfLiteMmapRo)
236 {
237 continue;
238 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100239
240 auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
241 armnn::IConnectableLayer* layer = delegateData.m_Network->AddInputLayer(bindingId);
242
243 auto tensorInfo = GetTensorInfoForTfLiteTensor(tensor);
244 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
245 outputSlot.SetTensorInfo(tensorInfo);
246
247 // Store for creating connections
Finn Williams6f9f9902020-11-13 13:23:15 +0000248 delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] = &outputSlot;
Sadik Armagan62483be2020-10-23 17:14:43 +0100249
Sadik Armagan6e36a642020-11-10 21:18:41 +0000250 inputBindings.push_back(std::make_pair(bindingId, tensorInfo));
Sadik Armagan62483be2020-10-23 17:14:43 +0100251 }
Sadik Armagan6e36a642020-11-10 21:18:41 +0000252
Sadik Armagan62483be2020-10-23 17:14:43 +0100253 return kTfLiteOk;
254}
255
256TfLiteStatus ArmnnSubgraph::AddOutputLayer(DelegateData& delegateData,
257 TfLiteContext* tfLiteContext,
258 const TfLiteIntArray* outputs,
259 std::vector<armnn::BindingPointInfo>& outputBindings)
260{
Finn Williams6f9f9902020-11-13 13:23:15 +0000261 const size_t numOutputs = static_cast<size_t>(outputs->size);
Sadik Armagan62483be2020-10-23 17:14:43 +0100262 for (unsigned int i = 0; i < numOutputs; ++i)
263 {
264 const int32_t tensorId = outputs->data[i];
265 const TfLiteTensor tensor = tfLiteContext->tensors[tensorId];
266
267 auto bindingId = static_cast<armnn::LayerBindingId>((tensorId));
268 armnn::IConnectableLayer* layer = delegateData.m_Network->AddOutputLayer(bindingId);
269
270 auto tensorInfo = GetTensorInfoForTfLiteTensor(tensor);
Finn Williams6f9f9902020-11-13 13:23:15 +0000271 ARMNN_ASSERT(delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)] != nullptr);
272 delegateData.m_OutputSlotForNode[static_cast<unsigned long>(tensorId)]->Connect(layer->GetInputSlot(0));
Sadik Armagan62483be2020-10-23 17:14:43 +0100273 outputBindings.push_back(std::make_pair(bindingId, tensorInfo));
274 }
275
276 return kTfLiteOk;
277}
278
Sadik Armagan3c24f432020-10-19 17:35:30 +0100279ArmnnSubgraph* ArmnnSubgraph::Create(TfLiteContext* tfLiteContext,
280 const TfLiteDelegateParams* parameters,
281 const Delegate* delegate)
282{
283 TfLiteIntArray* executionPlan;
284 if (tfLiteContext->GetExecutionPlan(tfLiteContext, &executionPlan) != kTfLiteOk)
285 {
286 return nullptr;
287 }
288
Sadik Armagan62483be2020-10-23 17:14:43 +0100289 // Initialize DelegateData holds network and output slots information
290 DelegateData delegateData(delegate->m_Options.GetBackends());
291
292 // Build ArmNN Network
Sadik Armagan3c24f432020-10-19 17:35:30 +0100293 armnn::NetworkOptions networkOptions = {};
294 armnn::NetworkId networkId;
Sadik Armagan62483be2020-10-23 17:14:43 +0100295 delegateData.m_Network = armnn::INetwork::Create(networkOptions);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100296
Sadik Armagan6e36a642020-11-10 21:18:41 +0000297 delegateData.m_OutputSlotForNode = std::vector<armnn::IOutputSlot*>(tfLiteContext->tensors_size, nullptr);
298
Sadik Armagan62483be2020-10-23 17:14:43 +0100299 std::vector<armnn::BindingPointInfo> inputBindings;
300 std::vector<armnn::BindingPointInfo> outputBindings;
301
302 // Add input layer
303 auto status = AddInputLayer(delegateData, tfLiteContext, parameters->input_tensors, inputBindings);
304 if (status != kTfLiteOk)
305 {
306 throw armnn::Exception("TfLiteArmnnDelegate: Unable to add Inputs to the network!");
307 }
308
309 // Parse TfLite delegate nodes to ArmNN
Sadik Armagan3c24f432020-10-19 17:35:30 +0100310 for (int i = 0; i < parameters->nodes_to_replace->size; ++i)
311 {
312 const int nodeIndex = parameters->nodes_to_replace->data[i];
313
314 TfLiteNode* tfLiteNode = nullptr;
315 TfLiteRegistration* tfLiteRegistration = nullptr;
316 if (tfLiteContext->GetNodeAndRegistration(
317 tfLiteContext, nodeIndex, &tfLiteNode, &tfLiteRegistration) != kTfLiteOk)
318 {
Finn Williams6f9f9902020-11-13 13:23:15 +0000319 throw armnn::Exception(&"TfLiteArmnnDelegate: Unable to get node registration: " [ nodeIndex]);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100320 }
321
Sadik Armagan62483be2020-10-23 17:14:43 +0100322 if (VisitNode(delegateData, tfLiteContext, tfLiteRegistration, tfLiteNode, nodeIndex) != kTfLiteOk)
Sadik Armagan3c24f432020-10-19 17:35:30 +0100323 {
Finn Williams6f9f9902020-11-13 13:23:15 +0000324 throw armnn::Exception(&"TfLiteArmnnDelegate: Unable to parse node: " [ nodeIndex]);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100325 }
326 }
327
Sadik Armagan62483be2020-10-23 17:14:43 +0100328 // Add Output layer
329 status = AddOutputLayer(delegateData, tfLiteContext, parameters->output_tensors, outputBindings);
330 if (status != kTfLiteOk)
331 {
332 throw armnn::Exception("TfLiteArmnnDelegate: Unable to add Outputs to the network!");
333 }
334
335 // Optimize ArmNN network
336 armnn::IOptimizedNetworkPtr optNet(nullptr, nullptr);
337 try
338 {
Sadik Armagan6e36a642020-11-10 21:18:41 +0000339 optNet = armnn::Optimize(*(delegateData.m_Network.get()),
Sadik Armagan62483be2020-10-23 17:14:43 +0100340 delegate->m_Options.GetBackends(),
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000341 delegate->m_Runtime->GetDeviceSpec(),
342 delegate->m_Options.GetOptimizerOptions());
Sadik Armagan62483be2020-10-23 17:14:43 +0100343 }
344 catch (std::exception &ex)
345 {
346 std::stringstream exMessage;
347 exMessage << "TfLiteArmnnDelegate: Exception (" << ex.what() << ") caught from optimize.";
348 throw armnn::Exception(exMessage.str());
349 }
Sadik Armagan3c24f432020-10-19 17:35:30 +0100350 if (!optNet)
351 {
Sadik Armagan62483be2020-10-23 17:14:43 +0100352 // Optimize failed
Sadik Armagan3c24f432020-10-19 17:35:30 +0100353 throw armnn::Exception("TfLiteArmnnDelegate: Unable to optimize the network!");
354 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100355
Colm Donelan3e32a872021-10-04 22:55:37 +0100356 // If set, we will serialize the optimized model into a dot file.
357 const std::string serializeToDotFile = delegate->m_Options.GetSerializeToDot();
358 if (!serializeToDotFile.empty())
359 {
360 fs::path filename = serializeToDotFile;
361 std::fstream file(filename.c_str(), std::ios_base::out);
362 optNet->SerializeToDot(file);
363 }
364
Sadik Armagan62483be2020-10-23 17:14:43 +0100365 try
366 {
367 // Load graph into runtime
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000368 std::string errorMessage;
Narumol Prangnawarat74a3cf52021-01-29 15:38:54 +0000369 armnn::Status loadingStatus;
Colm Donelan3e32a872021-10-04 22:55:37 +0100370 armnn::MemorySource memorySource = armnn::MemorySource::Undefined;
Narumol Prangnawarat74a3cf52021-01-29 15:38:54 +0000371 if (delegate->m_Options.GetOptimizerOptions().m_ImportEnabled)
372 {
Colm Donelan3e32a872021-10-04 22:55:37 +0100373 memorySource = armnn::MemorySource::Malloc;
Narumol Prangnawarat74a3cf52021-01-29 15:38:54 +0000374 }
Colm Donelan3e32a872021-10-04 22:55:37 +0100375 armnn::INetworkProperties networkProperties(false,
376 memorySource,
377 memorySource,
378 delegate->m_Options.GetInternalProfilingState(),
379 delegate->m_Options.GetInternalProfilingDetail());
380 loadingStatus = delegate->m_Runtime->LoadNetwork(networkId,
381 std::move(optNet),
382 errorMessage,
383 networkProperties);
Sadik Armagan62483be2020-10-23 17:14:43 +0100384 if (loadingStatus != armnn::Status::Success)
385 {
Colm Donelan45142282021-10-21 23:39:52 +0100386 // Network load failed.
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000387 throw armnn::Exception("TfLiteArmnnDelegate: Network could not be loaded:" + errorMessage);
Sadik Armagan62483be2020-10-23 17:14:43 +0100388 }
389 }
390 catch (std::exception& ex)
391 {
392 std::stringstream exMessage;
393 exMessage << "TfLiteArmnnDelegate: Exception (" << ex.what() << ") caught from LoadNetwork.";
394 throw armnn::Exception(exMessage.str());
395 }
Sadik Armagan3c24f432020-10-19 17:35:30 +0100396
Narumol Prangnawarat0b51d5a2021-01-20 15:58:29 +0000397 // Register debug callback function
398 if (delegate->m_Options.GetDebugCallbackFunction().has_value())
399 {
400 delegate->m_Runtime->RegisterDebugCallback(networkId, delegate->m_Options.GetDebugCallbackFunction().value());
401 }
402
Sadik Armagan3c24f432020-10-19 17:35:30 +0100403 // Create a new SubGraph with networkId and runtime
Sadik Armagan62483be2020-10-23 17:14:43 +0100404 return new ArmnnSubgraph(networkId, delegate->m_Runtime.get(), inputBindings, outputBindings);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100405}
406
407TfLiteStatus ArmnnSubgraph::Prepare(TfLiteContext* tfLiteContext)
408{
Finn Williams6f9f9902020-11-13 13:23:15 +0000409 armnn::IgnoreUnused(tfLiteContext);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100410 return kTfLiteOk;
411}
412
Sadik Armagan62483be2020-10-23 17:14:43 +0100413TfLiteStatus ArmnnSubgraph::Invoke(TfLiteContext* tfLiteContext, TfLiteNode* tfLiteNode)
Sadik Armagan3c24f432020-10-19 17:35:30 +0100414{
Sadik Armagan62483be2020-10-23 17:14:43 +0100415 // Prepare inputs
416 armnn::InputTensors inputTensors;
417 size_t inputIndex = 0;
418 for (auto inputIdx : tflite::TfLiteIntArrayView(tfLiteNode->inputs))
419 {
420 TfLiteTensor* tensor = &tfLiteContext->tensors[inputIdx];
421 if (tensor->allocation_type != kTfLiteMmapRo)
422 {
423 const armnn::BindingPointInfo& inputBinding = m_InputBindings[inputIndex];
424 const armnn::ConstTensor inputTensor(inputBinding.second, tensor->data.data);
425 inputTensors.emplace_back(inputIdx, inputTensor);
Sadik Armagan3c24f432020-10-19 17:35:30 +0100426
Sadik Armagan62483be2020-10-23 17:14:43 +0100427 ++inputIndex;
428 }
429 }
430
431 // Prepare outputs
432 armnn::OutputTensors outputTensors;
433 size_t outputIndex = 0;
434 for (auto outputIdx : tflite::TfLiteIntArrayView(tfLiteNode->outputs))
435 {
436 const armnn::BindingPointInfo& outputBinding = m_OutputBindings[outputIndex];
437 TfLiteTensor* tensor = &tfLiteContext->tensors[outputIdx];
438 const armnn::Tensor outputTensor(outputBinding.second, tensor->data.data);
439 outputTensors.emplace_back(outputIdx, outputTensor);
440
441 ++outputIndex;
442 }
443
444 // Run graph
445 auto status = m_Runtime->EnqueueWorkload(m_NetworkId, inputTensors, outputTensors);
Colm Donelan45142282021-10-21 23:39:52 +0100446 // The delegate holds its own Arm NN runtime so this is our last chance to print internal profiling data.
447 std::shared_ptr<armnn::IProfiler> profiler = m_Runtime->GetProfiler(m_NetworkId);
448 if (profiler && profiler->IsProfilingEnabled())
449 {
450 profiler->Print(std::cout);
451 }
Sadik Armagan62483be2020-10-23 17:14:43 +0100452 return (status == armnn::Status::Success) ? kTfLiteOk : kTfLiteError;
Sadik Armagan3c24f432020-10-19 17:35:30 +0100453}
454
Sadik Armagan62483be2020-10-23 17:14:43 +0100455TfLiteStatus ArmnnSubgraph::VisitNode(DelegateData& delegateData,
Sadik Armagan3c24f432020-10-19 17:35:30 +0100456 TfLiteContext* tfLiteContext,
457 TfLiteRegistration* tfLiteRegistration,
458 TfLiteNode* tfLiteNode,
459 int nodeIndex)
460{
Sadik Armagan62483be2020-10-23 17:14:43 +0100461 switch (tfLiteRegistration->builtin_code)
462 {
463 case kTfLiteBuiltinAbs:
464 return VisitElementwiseUnaryOperator(delegateData,
465 tfLiteContext,
466 tfLiteNode,
467 nodeIndex,
468 armnn::UnaryOperation::Abs);
469 case kTfLiteBuiltinAdd:
470 return VisitElementwiseBinaryOperator(delegateData,
471 tfLiteContext,
472 tfLiteNode,
473 nodeIndex,
474 kTfLiteBuiltinAdd);
475 case kTfLiteBuiltinArgMax:
476 return VisitArgMinMaxOperator(delegateData,
477 tfLiteContext,
478 tfLiteNode,
479 nodeIndex,
480 kTfLiteBuiltinArgMax);
481 case kTfLiteBuiltinArgMin:
482 return VisitArgMinMaxOperator(delegateData,
483 tfLiteContext,
484 tfLiteNode,
485 nodeIndex,
486 kTfLiteBuiltinArgMin);
487 case kTfLiteBuiltinAveragePool2d:
488 return VisitPoolingOperator(delegateData,
489 tfLiteContext,
490 tfLiteNode,
491 nodeIndex,
492 kTfLiteBuiltinAveragePool2d);
493 case kTfLiteBuiltinBatchToSpaceNd:
494 return VisitBatchToSpaceNdOperator(delegateData,
495 tfLiteContext,
496 tfLiteNode,
497 nodeIndex,
498 kTfLiteBuiltinBatchToSpaceNd);
Sadik Armagan937565b2021-04-21 14:03:28 +0100499 case kTfLiteBuiltinCast:
500 return VisitCastOperator(delegateData,
501 tfLiteContext,
502 tfLiteNode,
503 nodeIndex,
504 kTfLiteBuiltinCast);
Sadik Armagan62483be2020-10-23 17:14:43 +0100505 case kTfLiteBuiltinConcatenation:
506 return VisitControlOperator(delegateData,
507 tfLiteContext,
508 tfLiteNode,
509 nodeIndex,
510 kTfLiteBuiltinConcatenation);
511 case kTfLiteBuiltinConv2d:
512 return VisitConvolutionOperator(delegateData,
513 tfLiteContext,
514 tfLiteNode,
515 nodeIndex,
516 kTfLiteBuiltinConv2d);
Matthew Sloyan81ec9942021-10-12 10:26:30 +0100517// Conv3d is only correctly supported for external delegates from TF Lite v2.6, as there was a breaking bug in v2.5.
518#if defined(ARMNN_POST_TFLITE_2_5)
519 case kTfLiteBuiltinConv3d:
520 return VisitConvolutionOperator(delegateData,
521 tfLiteContext,
522 tfLiteNode,
523 nodeIndex,
524 kTfLiteBuiltinConv3d);
525#endif
Sadik Armagan62483be2020-10-23 17:14:43 +0100526 case kTfLiteBuiltinDepthToSpace:
527 return VisitDepthToSpaceOperator(delegateData,
528 tfLiteContext,
529 tfLiteNode,
530 nodeIndex,
531 kTfLiteBuiltinDepthToSpace);
532 case kTfLiteBuiltinDepthwiseConv2d:
533 return VisitConvolutionOperator(delegateData,
534 tfLiteContext,
535 tfLiteNode,
536 nodeIndex,
537 kTfLiteBuiltinDepthwiseConv2d);
538 case kTfLiteBuiltinDequantize:
539 return VisitDequantizeOperator(delegateData,
540 tfLiteContext,
541 tfLiteNode,
542 nodeIndex,
543 kTfLiteBuiltinDequantize);
544 case kTfLiteBuiltinDiv:
545 return VisitElementwiseBinaryOperator(delegateData,
546 tfLiteContext,
547 tfLiteNode,
548 nodeIndex,
549 kTfLiteBuiltinDiv);
550 case kTfLiteBuiltinElu:
551 return VisitActivationOperator(delegateData,
552 tfLiteContext,
553 tfLiteNode,
554 nodeIndex,
555 kTfLiteBuiltinElu);
556 case kTfLiteBuiltinEqual:
557 return VisitComparisonOperator(delegateData,
558 tfLiteContext,
559 tfLiteNode,
560 nodeIndex,
561 kTfLiteBuiltinEqual);
562 case kTfLiteBuiltinExp:
563 return VisitElementwiseUnaryOperator(delegateData,
564 tfLiteContext,
565 tfLiteNode,
566 nodeIndex,
567 armnn::UnaryOperation::Exp);
568 case kTfLiteBuiltinExpandDims:
569 return VisitExpandDimsOperator(delegateData,
570 tfLiteContext,
571 tfLiteNode,
572 nodeIndex,
573 kTfLiteBuiltinExpandDims);
574 case kTfLiteBuiltinFill:
575 return VisitFillOperator(delegateData,
576 tfLiteContext,
577 tfLiteNode,
578 nodeIndex,
579 kTfLiteBuiltinFill);
580 case kTfLiteBuiltinFloor:
581 return VisitFloorOperator(delegateData,
582 tfLiteContext,
583 tfLiteNode,
584 nodeIndex,
585 kTfLiteBuiltinFloor);
586 case kTfLiteBuiltinFullyConnected:
587 return VisitFullyConnectedOperator(delegateData,
588 tfLiteContext,
589 tfLiteNode,
590 nodeIndex,
591 kTfLiteBuiltinFullyConnected);
592 case kTfLiteBuiltinGather:
593 return VisitGatherOperator(delegateData,
594 tfLiteContext,
595 tfLiteNode,
596 nodeIndex,
597 kTfLiteBuiltinGather);
598 case kTfLiteBuiltinGatherNd:
599 return VisitGatherOperator(delegateData,
600 tfLiteContext,
601 tfLiteNode,
602 nodeIndex,
603 kTfLiteBuiltinGatherNd);
604 case kTfLiteBuiltinGreater:
605 return VisitComparisonOperator(delegateData,
606 tfLiteContext,
607 tfLiteNode,
608 nodeIndex,
609 kTfLiteBuiltinGreater);
610 case kTfLiteBuiltinGreaterEqual:
611 return VisitComparisonOperator(delegateData,
612 tfLiteContext,
613 tfLiteNode,
614 nodeIndex,
615 kTfLiteBuiltinGreaterEqual);
616 case kTfLiteBuiltinHardSwish:
617 return VisitActivationOperator(delegateData,
618 tfLiteContext,
619 tfLiteNode,
620 nodeIndex,
621 kTfLiteBuiltinHardSwish);
622 case kTfLiteBuiltinL2Normalization:
Sadik Armagan4b227bb2021-01-22 10:53:38 +0000623 return VisitL2NormalizationOperator(delegateData,
624 tfLiteContext,
625 tfLiteNode,
626 nodeIndex,
627 kTfLiteBuiltinL2Normalization);
Sadik Armagan62483be2020-10-23 17:14:43 +0100628 case kTfLiteBuiltinL2Pool2d:
629 return VisitPoolingOperator(delegateData,
630 tfLiteContext,
631 tfLiteNode,
632 nodeIndex,
633 kTfLiteBuiltinL2Pool2d);
634 case kTfLiteBuiltinLess:
635 return VisitComparisonOperator(delegateData,
636 tfLiteContext,
637 tfLiteNode,
638 nodeIndex,
639 kTfLiteBuiltinLess);
640 case kTfLiteBuiltinLessEqual:
641 return VisitComparisonOperator(delegateData,
642 tfLiteContext,
643 tfLiteNode,
644 nodeIndex,
645 kTfLiteBuiltinLessEqual);
646 case kTfLiteBuiltinLocalResponseNormalization:
Sadik Armagan4b227bb2021-01-22 10:53:38 +0000647 return VisitLocalResponseNormalizationOperator(delegateData,
648 tfLiteContext,
649 tfLiteNode,
650 nodeIndex,
651 kTfLiteBuiltinLocalResponseNormalization);
Matthew Sloyanc8eb9552020-11-26 10:54:22 +0000652 case kTfLiteBuiltinLogicalAnd:
653 return VisitLogicalBinaryOperator(delegateData,
654 tfLiteContext,
655 tfLiteNode,
656 nodeIndex,
657 kTfLiteBuiltinLogicalAnd,
658 armnn::LogicalBinaryOperation::LogicalAnd);
659 case kTfLiteBuiltinLogicalNot:
660 return VisitElementwiseUnaryOperator(delegateData,
661 tfLiteContext,
662 tfLiteNode,
663 nodeIndex,
664 armnn::UnaryOperation::LogicalNot);
665 case kTfLiteBuiltinLogicalOr:
666 return VisitLogicalBinaryOperator(delegateData,
667 tfLiteContext,
668 tfLiteNode,
669 nodeIndex,
670 kTfLiteBuiltinLogicalOr,
671 armnn::LogicalBinaryOperation::LogicalOr);
Sadik Armagan62483be2020-10-23 17:14:43 +0100672 case kTfLiteBuiltinLogistic:
673 return VisitActivationOperator(delegateData,
674 tfLiteContext,
675 tfLiteNode,
676 nodeIndex,
677 kTfLiteBuiltinLogistic);
678 case kTfLiteBuiltinLogSoftmax:
679 return VisitSoftmaxOperator(delegateData,
680 tfLiteContext,
681 tfLiteNode,
682 nodeIndex,
683 kTfLiteBuiltinLogSoftmax);
684 case kTfLiteBuiltinLstm:
685 return VisitLstmOperator(delegateData,
686 tfLiteContext,
687 tfLiteNode,
688 nodeIndex,
689 kTfLiteBuiltinLstm);
690 case kTfLiteBuiltinMaxPool2d:
691 return VisitPoolingOperator(delegateData,
692 tfLiteContext,
693 tfLiteNode,
694 nodeIndex,
695 kTfLiteBuiltinMaxPool2d);
696 case kTfLiteBuiltinMaximum:
697 return VisitElementwiseBinaryOperator(delegateData,
698 tfLiteContext,
699 tfLiteNode,
700 nodeIndex,
701 kTfLiteBuiltinMaximum);
702 case kTfLiteBuiltinMean:
703 return VisitControlOperator(delegateData,
704 tfLiteContext,
705 tfLiteNode,
706 nodeIndex,
707 kTfLiteBuiltinMean);
708 case kTfLiteBuiltinMinimum:
709 return VisitElementwiseBinaryOperator(delegateData,
710 tfLiteContext,
711 tfLiteNode,
712 nodeIndex,
713 kTfLiteBuiltinMinimum);
Matthew Sloyanaf3a4ef2021-10-22 15:48:12 +0100714 case kTfLiteBuiltinMirrorPad:
715 return VisitPadOperator(delegateData,
716 tfLiteContext,
717 tfLiteNode,
718 nodeIndex,
719 kTfLiteBuiltinMirrorPad);
Sadik Armagan62483be2020-10-23 17:14:43 +0100720 case kTfLiteBuiltinMul:
721 return VisitElementwiseBinaryOperator(delegateData,
722 tfLiteContext,
723 tfLiteNode,
724 nodeIndex,
725 kTfLiteBuiltinMul);
726 case kTfLiteBuiltinNeg:
727 return VisitElementwiseUnaryOperator(delegateData,
728 tfLiteContext,
729 tfLiteNode,
730 nodeIndex,
731 armnn::UnaryOperation::Neg);
732 case kTfLiteBuiltinNotEqual:
733 return VisitComparisonOperator(delegateData,
734 tfLiteContext,
735 tfLiteNode,
736 nodeIndex,
737 kTfLiteBuiltinNotEqual);
Matthew Sloyana7a12f52021-05-06 10:05:28 +0100738 case kTfLiteBuiltinPack:
739 return VisitPackOperator(delegateData,
740 tfLiteContext,
741 tfLiteNode,
742 nodeIndex,
743 kTfLiteBuiltinPack);
Sadik Armagan62483be2020-10-23 17:14:43 +0100744 case kTfLiteBuiltinPad:
745 return VisitPadOperator(delegateData,
746 tfLiteContext,
747 tfLiteNode,
748 nodeIndex,
749 kTfLiteBuiltinPad);
750 case kTfLiteBuiltinPadv2:
751 return VisitPadOperator(delegateData,
752 tfLiteContext,
753 tfLiteNode,
754 nodeIndex,
755 kTfLiteBuiltinPadv2);
756 case kTfLiteBuiltinPrelu:
James Conroy39825482021-05-27 17:44:50 +0100757 return VisitPreluOperator(delegateData,
758 tfLiteContext,
759 tfLiteNode,
760 nodeIndex,
761 kTfLiteBuiltinPrelu);
Sadik Armagan62483be2020-10-23 17:14:43 +0100762 case kTfLiteBuiltinQuantize:
763 return VisitQuantizeOperator(delegateData,
764 tfLiteContext,
765 tfLiteNode,
766 nodeIndex,
767 kTfLiteBuiltinQuantize);
768 case kTfLiteBuiltinRank:
769 return VisitControlOperator(delegateData,
770 tfLiteContext,
771 tfLiteNode,
772 nodeIndex,
773 kTfLiteBuiltinRank);
Sadik Armagana2747482021-02-09 10:28:54 +0000774 case kTfLiteBuiltinReduceMax:
775 return VisitReduceOperator(delegateData,
776 tfLiteContext,
777 tfLiteNode,
778 nodeIndex,
779 kTfLiteBuiltinReduceMax);
780 case kTfLiteBuiltinReduceMin:
781 return VisitReduceOperator(delegateData,
782 tfLiteContext,
783 tfLiteNode,
784 nodeIndex,
785 kTfLiteBuiltinReduceMin);
Teresa Charlin4e3e8312021-08-05 12:34:37 +0100786 case kTfLiteBuiltinReduceProd:
787 return VisitReduceOperator(delegateData,
788 tfLiteContext,
789 tfLiteNode,
790 nodeIndex,
791 kTfLiteBuiltinReduceProd);
Sadik Armagan62483be2020-10-23 17:14:43 +0100792 case kTfLiteBuiltinRelu:
793 return VisitActivationOperator(delegateData,
794 tfLiteContext,
795 tfLiteNode,
796 nodeIndex,
797 kTfLiteBuiltinRelu);
798 case kTfLiteBuiltinReluN1To1:
799 return VisitActivationOperator(delegateData,
800 tfLiteContext,
801 tfLiteNode,
802 nodeIndex,
803 kTfLiteBuiltinReluN1To1);
804 case kTfLiteBuiltinRelu6:
805 return VisitActivationOperator(delegateData,
806 tfLiteContext,
807 tfLiteNode,
808 nodeIndex,
809 kTfLiteBuiltinRelu6);
810 case kTfLiteBuiltinReshape:
811 return VisitReshapeOperator(delegateData,
812 tfLiteContext,
813 tfLiteNode,
814 nodeIndex,
815 kTfLiteBuiltinReshape);
816 case kTfLiteBuiltinResizeBilinear:
817 return VisitResizeOperator(delegateData,
818 tfLiteContext,
819 tfLiteNode,
820 nodeIndex,
821 kTfLiteBuiltinResizeBilinear);
822 case kTfLiteBuiltinResizeNearestNeighbor:
823 return VisitResizeOperator(delegateData,
824 tfLiteContext,
825 tfLiteNode,
826 nodeIndex,
827 kTfLiteBuiltinResizeNearestNeighbor);
828 case kTfLiteBuiltinRsqrt:
829 return VisitElementwiseUnaryOperator(delegateData,
830 tfLiteContext,
831 tfLiteNode,
832 nodeIndex,
833 armnn::UnaryOperation::Rsqrt);
Keith Davis0176fd82021-06-01 17:36:32 +0100834 case kTfLiteBuiltinShape:
835 return VisitShapeOperator(delegateData,
836 tfLiteContext,
837 tfLiteNode,
838 nodeIndex,
839 kTfLiteBuiltinShape);
Sadik Armagan34fa1bd2020-11-27 12:40:52 +0000840 case kTfLiteBuiltinSplit:
841 return VisitSplitOperator(delegateData,
842 tfLiteContext,
843 tfLiteNode,
844 nodeIndex,
845 kTfLiteBuiltinSplit);
846 case kTfLiteBuiltinSplitV:
847 return VisitSplitVOperator(delegateData,
848 tfLiteContext,
849 tfLiteNode,
850 nodeIndex,
851 kTfLiteBuiltinSplitV);
Sadik Armagan62483be2020-10-23 17:14:43 +0100852 case kTfLiteBuiltinSqrt:
853 return VisitElementwiseUnaryOperator(delegateData,
854 tfLiteContext,
855 tfLiteNode,
856 nodeIndex,
857 armnn::UnaryOperation::Sqrt);
858 case kTfLiteBuiltinSqueeze:
859 return VisitSqueezeOperator(delegateData,
860 tfLiteContext,
861 tfLiteNode,
862 nodeIndex,
863 kTfLiteBuiltinSqueeze);
864 case kTfLiteBuiltinStridedSlice:
865 return VisitSliceOperator(delegateData,
866 tfLiteContext,
867 tfLiteNode,
868 nodeIndex,
869 kTfLiteBuiltinStridedSlice);
Sadik Armagana2747482021-02-09 10:28:54 +0000870 case kTfLiteBuiltinSum:
871 return VisitReduceOperator(delegateData,
872 tfLiteContext,
873 tfLiteNode,
874 nodeIndex,
875 kTfLiteBuiltinSum);
Sadik Armagan62483be2020-10-23 17:14:43 +0100876 case kTfLiteBuiltinTranspose:
877 return VisitTransposeOperator(delegateData,
878 tfLiteContext,
879 tfLiteNode,
880 nodeIndex,
881 kTfLiteBuiltinTranspose);
882 case kTfLiteBuiltinTransposeConv:
883 return VisitConvolutionOperator(delegateData,
884 tfLiteContext,
885 tfLiteNode,
886 nodeIndex,
887 kTfLiteBuiltinTransposeConv);
888 case kTfLiteBuiltinSoftmax:
889 return VisitSoftmaxOperator(delegateData,
890 tfLiteContext,
891 tfLiteNode,
892 nodeIndex,
893 kTfLiteBuiltinSoftmax);
894 case kTfLiteBuiltinSpaceToBatchNd:
895 return VisitSpaceToBatchNdOperator(delegateData,
896 tfLiteContext,
897 tfLiteNode,
898 nodeIndex,
899 kTfLiteBuiltinSpaceToBatchNd);
900 case kTfLiteBuiltinSpaceToDepth:
901 return VisitSpaceToDepthOperator(delegateData,
902 tfLiteContext,
903 tfLiteNode,
904 nodeIndex,
905 kTfLiteBuiltinSpaceToDepth);
906 case kTfLiteBuiltinSub:
907 return VisitElementwiseBinaryOperator(delegateData,
908 tfLiteContext,
909 tfLiteNode,
910 nodeIndex,
911 kTfLiteBuiltinSub);
912 case kTfLiteBuiltinTanh:
913 return VisitActivationOperator(delegateData,
914 tfLiteContext,
915 tfLiteNode,
916 nodeIndex,
917 kTfLiteBuiltinTanh);
Narumol Prangnawarat7684b182021-08-12 14:48:15 +0100918 case kTfLiteBuiltinUnidirectionalSequenceLstm:
919 return VisitUnidirectionalSequenceLstmOperator(delegateData,
920 tfLiteContext,
921 tfLiteNode,
922 nodeIndex,
923 kTfLiteBuiltinUnidirectionalSequenceLstm);
Kevin May8ab2d7a2021-05-07 09:32:51 +0100924 case kTfLiteBuiltinUnpack:
925 return VisitUnpackOperator(delegateData,
926 tfLiteContext,
927 tfLiteNode,
928 nodeIndex,
929 kTfLiteBuiltinUnpack);
Sadik Armagan62483be2020-10-23 17:14:43 +0100930 default:
931 return kTfLiteError;
932 }
Sadik Armagan3c24f432020-10-19 17:35:30 +0100933}
934
935} // armnnDelegate namespace