blob: c205a57583d1edb36397199e5fd75ca4eb859f70 [file] [log] [blame]
telsoa015307bc12018-03-09 13:51:08 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beck93e48982018-09-05 13:05:09 +01003// SPDX-License-Identifier: MIT
telsoa015307bc12018-03-09 13:51:08 +00004//
5
6#define LOG_TAG "ArmnnDriver"
7
8#include "ModelToINetworkConverter.hpp"
Kevin May42477c12020-03-26 13:34:14 +00009#include "Utils.hpp"
telsoa015307bc12018-03-09 13:51:08 +000010
11#include <log/log.h>
Kevin May42477c12020-03-26 13:34:14 +000012#include <type_traits>
telsoa01ce3e84a2018-08-31 09:31:35 +010013
surmeh0149b9e102018-05-17 14:11:25 +010014namespace armnn_driver
15{
kevmay01bc5f7842018-08-30 12:34:39 +010016
arovir01b0717b52018-09-05 17:03:25 +010017template<typename HalPolicy>
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +010018ModelToINetworkConverter<HalPolicy>::ModelToINetworkConverter(const std::vector<armnn::BackendId>& backends,
kevmay01bc5f7842018-08-30 12:34:39 +010019 const HalModel& model,
telsoa015307bc12018-03-09 13:51:08 +000020 const std::set<unsigned int>& forcedUnsupportedOperations)
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +010021 : m_Data(backends)
telsoa015307bc12018-03-09 13:51:08 +000022 , m_Model(model)
23 , m_ForcedUnsupportedOperations(forcedUnsupportedOperations)
telsoa015307bc12018-03-09 13:51:08 +000024 , m_ConversionResult(ConversionResult::Success)
25{
26 try
27 {
28 Convert();
29 }
Derek Lambertib9cb8442019-11-28 13:34:48 +000030 catch (std::exception& e)
telsoa015307bc12018-03-09 13:51:08 +000031 {
32 m_ConversionResult = ConversionResult::UnsupportedFeature;
33 ALOGE("%s: Unexpected exception: %s", __func__, e.what());
34 assert(false);
35 }
36}
37
arovir01b0717b52018-09-05 17:03:25 +010038template<typename HalPolicy>
39void ModelToINetworkConverter<HalPolicy>::Convert()
telsoa015307bc12018-03-09 13:51:08 +000040{
Sadik Armagan44bcc022019-06-18 17:21:36 +010041 using HalModel = typename HalPolicy::Model;
42 using HalOperand = typename HalPolicy::Operand;
43 using HalOperandType = typename HalPolicy::OperandType;
Matteo Martincighe48bdff2018-09-03 13:50:50 +010044
arovir01a15dc112018-09-03 17:12:56 +010045 ALOGV("ModelToINetworkConverter::Convert(): %s", GetModelSummary<HalModel>(m_Model).c_str());
telsoa015307bc12018-03-09 13:51:08 +000046
47 // map the memory pool into shared pointers
arovir01b0717b52018-09-05 17:03:25 +010048 m_Data.m_MemPools.clear();
49 if (!setRunTimePoolInfosFromHidlMemories(&m_Data.m_MemPools, m_Model.pools))
telsoa015307bc12018-03-09 13:51:08 +000050 {
51 Fail("%s: Setting of run time pool infos from Hidl Memories has failed.", __func__);
52 m_ConversionResult = ConversionResult::ErrorMappingPools;
53 return;
54 }
55
56 uint32_t totalPoolSize = 0;
57 for (auto&& pool : m_Model.pools)
58 {
59 totalPoolSize += pool.size();
60 }
61
Finn Williamsa4983ce2020-07-23 12:55:12 +010062 using NetworkOptions = std::vector<armnn::BackendOptions>;
63 NetworkOptions networkOptions;
64 armnn::BackendOptions shapeInferenceMethodOption("ShapeInferenceMethod",
65 {
66 { "InferAndValidate", true }
67 });
68
69 networkOptions.push_back(shapeInferenceMethodOption);
70
telsoa015307bc12018-03-09 13:51:08 +000071 // Create armnn::INetwork
Finn Williamsa4983ce2020-07-23 12:55:12 +010072 m_Data.m_Network = armnn::INetwork::Create(networkOptions);
telsoa015307bc12018-03-09 13:51:08 +000073
74 // add operations to it
75 // track which layer outputs each operand
Kevin May42477c12020-03-26 13:34:14 +000076 ALOGV("ModelToINetworkConverter::Convert(): m_OutputSlotForOperand");
77 m_Data.m_OutputSlotForOperand = std::vector<armnn::IOutputSlot*>(getMainModel(m_Model).operands.size(), nullptr);
telsoa015307bc12018-03-09 13:51:08 +000078 try
79 {
Kevin May42477c12020-03-26 13:34:14 +000080 ALOGV("ModelToINetworkConverter::Convert(): for getMainModel(m_Model).inputIndexes.size()");
81 for (uint32_t i = 0; i < getMainModel(m_Model).inputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +000082 {
Kevin May42477c12020-03-26 13:34:14 +000083 ALOGV("ModelToINetworkConverter::Convert(): getMainModel(m_Model).inputIndexes[i]");
telsoa015307bc12018-03-09 13:51:08 +000084 // inputs in android nn are represented by operands
Kevin May42477c12020-03-26 13:34:14 +000085 uint32_t inputIndex = getMainModel(m_Model).inputIndexes[i];
86 ALOGV("ModelToINetworkConverter::Convert(): getMainModel(m_Model).operands[inputIndex];");
87 const HalOperand& operand = getMainModel(m_Model).operands[inputIndex];
88 ALOGV("ModelToINetworkConverter::Convert(): GetTensorInfoForOperand(operand)");
telsoa015307bc12018-03-09 13:51:08 +000089 const armnn::TensorInfo& tensor = GetTensorInfoForOperand(operand);
Sadik Armaganb3021432021-01-13 15:56:51 +000090 const std::string layerName = "Input_" + std::to_string(i);
91 ALOGV("ModelToINetworkConverter::Convert(): m_Data.m_Network->AddInputLayer(i, layerName.c_str())");
92 armnn::IConnectableLayer* layer = m_Data.m_Network->AddInputLayer(i, layerName.c_str());
telsoa015307bc12018-03-09 13:51:08 +000093
Kevin May42477c12020-03-26 13:34:14 +000094 ALOGV("ModelToINetworkConverter::Convert(): layer->GetOutputSlot(0)");
telsoa015307bc12018-03-09 13:51:08 +000095 armnn::IOutputSlot& outputSlot = layer->GetOutputSlot(0);
Kevin May42477c12020-03-26 13:34:14 +000096 ALOGV("ModelToINetworkConverter::Convert(): outputSlot.SetTensorInfo(GetTensorInfoForOperand(operand))");
telsoa015307bc12018-03-09 13:51:08 +000097 outputSlot.SetTensorInfo(GetTensorInfoForOperand(operand));
98
Kevin May42477c12020-03-26 13:34:14 +000099 ALOGV("ModelToINetworkConverter::Convert(): m_Data.m_OutputSlotForOperand[inputIndex] = &outputSlot");
telsoa015307bc12018-03-09 13:51:08 +0000100 // store for later layers
arovir01b0717b52018-09-05 17:03:25 +0100101 m_Data.m_OutputSlotForOperand[inputIndex] = &outputSlot;
telsoa015307bc12018-03-09 13:51:08 +0000102 }
103 }
Sadik Armagan44bcc022019-06-18 17:21:36 +0100104 catch (UnsupportedOperand<HalOperandType>& e)
telsoa015307bc12018-03-09 13:51:08 +0000105 {
106 Fail("%s: Operand type %s not supported in ArmnnDriver", __func__, toString(e.m_type).c_str());
107 m_ConversionResult = ConversionResult::UnsupportedFeature;
108 }
109 catch (const armnn::InvalidArgumentException& e)
110 {
111 Fail("%s: Failed to convert input operand to TensorShape: %s", __func__, e.what());
112 m_ConversionResult = ConversionResult::UnsupportedFeature;
113 }
Finn Williams291a16b2020-08-19 22:54:00 +0100114 bool UnsupportedDynamicOperation = false;
Kevin May42477c12020-03-26 13:34:14 +0000115 for (uint32_t operationIdx = 0; operationIdx < getMainModel(m_Model).operations.size(); operationIdx++)
telsoa015307bc12018-03-09 13:51:08 +0000116 {
Kevin May42477c12020-03-26 13:34:14 +0000117 const auto& operation = getMainModel(m_Model).operations[operationIdx];
telsoa015307bc12018-03-09 13:51:08 +0000118
119 bool ok = true;
120 if (m_ForcedUnsupportedOperations.find(operationIdx) != m_ForcedUnsupportedOperations.end())
121 {
122 Fail("%s: Operation at index %i has been forced to be unsupported.", __func__, operationIdx);
123 ok = false;
124 }
125
126 if (ok)
127 {
128 try
129 {
arovir01b0717b52018-09-05 17:03:25 +0100130 ok = HalPolicy::ConvertOperation(operation, m_Model, m_Data);
telsoa015307bc12018-03-09 13:51:08 +0000131 }
Sadik Armagan44bcc022019-06-18 17:21:36 +0100132 catch (UnsupportedOperand<HalOperandType>& e)
telsoa015307bc12018-03-09 13:51:08 +0000133 {
134 Fail("%s: Operand type %s not supported in ArmnnDriver", __func__, toString(e.m_type).c_str());
135 ok = false;
136 }
137 catch (const armnn::InvalidArgumentException& e)
138 {
139 Fail("%s: Failed to convert operation in %s", __func__, e.what());
140 ok = false;
141 }
142 }
143
144 // Store whether this operation was successfully converted.
145 m_OperationSupported.emplace(operationIdx, ok);
146
147 // Any single operation failing will fail the entire conversion.
148 // We still need to continue and check the other ones.
149 if (!ok)
150 {
Finn Williams291a16b2020-08-19 22:54:00 +0100151 if (m_Data.m_DynamicInputsEncountered)
152 {
153 Fail("%s: The unsupported operation at index %i has dynamic inputs.", __func__, operationIdx);
154 UnsupportedDynamicOperation = true;
155 }
156
telsoa015307bc12018-03-09 13:51:08 +0000157 m_ConversionResult = ConversionResult::UnsupportedFeature;
158 }
Finn Williams291a16b2020-08-19 22:54:00 +0100159 m_Data.m_DynamicInputsEncountered = false;
telsoa015307bc12018-03-09 13:51:08 +0000160 }
Finn Williams291a16b2020-08-19 22:54:00 +0100161
162 // Due to the NNAPI partitioner not supporting partition boundaries of unknown size,
163 // any operations who's outputs connect to an unsupported operation with with dynamic inputs
164 // will cause a failure.
165
166 // The simplest solution to this problem is to not support any operations in a model containing
167 // an unsupported operation with with dynamic inputs.
168 if (UnsupportedDynamicOperation)
169 {
170 Fail("%s: Unsupported operation with dynamic inputs found. Retroactively setting all operations to unsupported",
171 __func__);
172 for (auto& operation : m_OperationSupported)
173 {
174 operation.second = false;
175 }
176 }
177
telsoa015307bc12018-03-09 13:51:08 +0000178 try
179 {
180 if (m_ConversionResult == ConversionResult::Success)
181 {
Kevin May42477c12020-03-26 13:34:14 +0000182 for (uint32_t i = 0; i < getMainModel(m_Model).outputIndexes.size(); i++)
telsoa015307bc12018-03-09 13:51:08 +0000183 {
184 // outputs in android nn are represented by operands
Kevin May42477c12020-03-26 13:34:14 +0000185 uint32_t outputIndex = getMainModel(m_Model).outputIndexes[i];
186 const HalOperand& operand = getMainModel(m_Model).operands[outputIndex];
telsoa015307bc12018-03-09 13:51:08 +0000187 const armnn::TensorInfo& tensor = GetTensorInfoForOperand(operand);
Sadik Armaganb3021432021-01-13 15:56:51 +0000188 const std::string layerName = "Output_" + std::to_string(i);
189 armnn::IConnectableLayer* layer = m_Data.m_Network->AddOutputLayer(i, layerName.c_str());
telsoa015307bc12018-03-09 13:51:08 +0000190
arovir01b0717b52018-09-05 17:03:25 +0100191 assert(m_Data.m_OutputSlotForOperand[outputIndex]);
192 m_Data.m_OutputSlotForOperand[outputIndex]->Connect(layer->GetInputSlot(0));
telsoa015307bc12018-03-09 13:51:08 +0000193 }
194 }
195 }
196 catch (const armnn::InvalidArgumentException& e)
197 {
198 Fail("%s: Failed to convert output operand to TensorShape: %s", __func__, e.what());
199 m_ConversionResult = ConversionResult::UnsupportedFeature;
200 }
201}
202
arovir01b0717b52018-09-05 17:03:25 +0100203template<typename HalPolicy>
204bool ModelToINetworkConverter<HalPolicy>::IsOperationSupported(uint32_t operationIndex) const
telsoa015307bc12018-03-09 13:51:08 +0000205{
206 std::map<uint32_t, bool>::const_iterator it = m_OperationSupported.find(operationIndex);
207 assert(it != m_OperationSupported.end());
208 return it->second;
209}
210
arovir01b0717b52018-09-05 17:03:25 +0100211///
212/// Class template specializations
213///
telsoa015307bc12018-03-09 13:51:08 +0000214
arovir01b0717b52018-09-05 17:03:25 +0100215template class ModelToINetworkConverter<hal_1_0::HalPolicy>;
216
Matteo Martincigh8b287c22018-09-07 09:25:10 +0100217#ifdef ARMNN_ANDROID_NN_V1_1
arovir01b0717b52018-09-05 17:03:25 +0100218template class ModelToINetworkConverter<hal_1_1::HalPolicy>;
kevmay01bc5f7842018-08-30 12:34:39 +0100219#endif
220
Mike Kellyb5fdf382019-06-11 16:35:25 +0100221#ifdef ARMNN_ANDROID_NN_V1_2
222template class ModelToINetworkConverter<hal_1_1::HalPolicy>;
223template class ModelToINetworkConverter<hal_1_2::HalPolicy>;
224#endif
225
Kevin May42477c12020-03-26 13:34:14 +0000226#ifdef ARMNN_ANDROID_NN_V1_3
227template class ModelToINetworkConverter<hal_1_1::HalPolicy>;
228template class ModelToINetworkConverter<hal_1_2::HalPolicy>;
229template class ModelToINetworkConverter<hal_1_3::HalPolicy>;
230#endif
231
Matteo Martincighe48bdff2018-09-03 13:50:50 +0100232} // armnn_driver