blob: ffe0752c11b4f89afc1f4840e75135704e2a034d [file] [log] [blame]
Michael Butlerb98aa6d2020-02-22 22:37:59 -08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Conversions.h"
18
19#include <android-base/logging.h>
20#include <android/hardware/neuralnetworks/1.0/types.h>
21#include <android/hardware/neuralnetworks/1.1/types.h>
22#include <nnapi/OperandTypes.h>
23#include <nnapi/OperationTypes.h>
24#include <nnapi/Result.h>
25#include <nnapi/SharedMemory.h>
26#include <nnapi/Types.h>
27#include <nnapi/hal/1.0/Conversions.h>
28#include <nnapi/hal/CommonUtils.h>
29
30#include <algorithm>
31#include <functional>
32#include <iterator>
33#include <type_traits>
34#include <utility>
35
36namespace android::nn {
37namespace {
38
39using hardware::hidl_vec;
40
41template <typename Input>
42using convertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
43
44template <typename Type>
Michael Butler4b276a72020-08-06 23:22:35 -070045GeneralResult<std::vector<convertOutput<Type>>> convert(const hidl_vec<Type>& arguments) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080046 std::vector<convertOutput<Type>> canonical;
47 canonical.reserve(arguments.size());
48 for (const auto& argument : arguments) {
49 canonical.push_back(NN_TRY(nn::convert(argument)));
50 }
51 return canonical;
52}
53
54} // anonymous namespace
55
Michael Butler4b276a72020-08-06 23:22:35 -070056GeneralResult<OperationType> convert(const hal::V1_1::OperationType& operationType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080057 return static_cast<OperationType>(operationType);
58}
59
Michael Butler4b276a72020-08-06 23:22:35 -070060GeneralResult<Capabilities> convert(const hal::V1_1::Capabilities& capabilities) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080061 const auto quantized8Performance = NN_TRY(convert(capabilities.quantized8Performance));
62 const auto float32Performance = NN_TRY(convert(capabilities.float32Performance));
63 const auto relaxedFloat32toFloat16Performance =
64 NN_TRY(convert(capabilities.relaxedFloat32toFloat16Performance));
65
66 auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance,
67 quantized8Performance);
68
69 return Capabilities{
70 .relaxedFloat32toFloat16PerformanceScalar = relaxedFloat32toFloat16Performance,
71 .relaxedFloat32toFloat16PerformanceTensor = relaxedFloat32toFloat16Performance,
72 .operandPerformance = std::move(table),
73 };
74}
75
Michael Butler4b276a72020-08-06 23:22:35 -070076GeneralResult<Operation> convert(const hal::V1_1::Operation& operation) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080077 return Operation{
78 .type = NN_TRY(convert(operation.type)),
79 .inputs = operation.inputs,
80 .outputs = operation.outputs,
81 };
82}
83
Michael Butler4b276a72020-08-06 23:22:35 -070084GeneralResult<Model> convert(const hal::V1_1::Model& model) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -080085 auto operations = NN_TRY(convert(model.operations));
86
87 // Verify number of consumers.
88 const auto numberOfConsumers =
89 hal::utils::countNumberOfConsumers(model.operands.size(), operations);
90 CHECK(model.operands.size() == numberOfConsumers.size());
91 for (size_t i = 0; i < model.operands.size(); ++i) {
92 if (model.operands[i].numberOfConsumers != numberOfConsumers[i]) {
Michael Butler4b276a72020-08-06 23:22:35 -070093 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
94 << "Invalid numberOfConsumers for operand " << i << ", expected "
95 << numberOfConsumers[i] << " but found " << model.operands[i].numberOfConsumers;
Michael Butlerb98aa6d2020-02-22 22:37:59 -080096 }
97 }
98
99 auto main = Model::Subgraph{
100 .operands = NN_TRY(convert(model.operands)),
101 .operations = std::move(operations),
102 .inputIndexes = model.inputIndexes,
103 .outputIndexes = model.outputIndexes,
104 };
105
106 return Model{
107 .main = std::move(main),
108 .operandValues = NN_TRY(convert(model.operandValues)),
109 .pools = NN_TRY(convert(model.pools)),
110 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
111 };
112}
113
Michael Butler4b276a72020-08-06 23:22:35 -0700114GeneralResult<ExecutionPreference> convert(
115 const hal::V1_1::ExecutionPreference& executionPreference) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800116 return static_cast<ExecutionPreference>(executionPreference);
117}
118
119} // namespace android::nn
120
121namespace android::hardware::neuralnetworks::V1_1::utils {
122namespace {
123
124using utils::convert;
125
Michael Butler4b276a72020-08-06 23:22:35 -0700126nn::GeneralResult<V1_0::PerformanceInfo> convert(
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800127 const nn::Capabilities::PerformanceInfo& performanceInfo) {
128 return V1_0::utils::convert(performanceInfo);
129}
130
Michael Butler4b276a72020-08-06 23:22:35 -0700131nn::GeneralResult<V1_0::Operand> convert(const nn::Operand& operand) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800132 return V1_0::utils::convert(operand);
133}
134
Michael Butler4b276a72020-08-06 23:22:35 -0700135nn::GeneralResult<hidl_vec<uint8_t>> convert(const nn::Model::OperandValues& operandValues) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800136 return V1_0::utils::convert(operandValues);
137}
138
Michael Butler4b276a72020-08-06 23:22:35 -0700139nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800140 return V1_0::utils::convert(memory);
141}
142
143template <typename Input>
144using convertOutput = std::decay_t<decltype(convert(std::declval<Input>()).value())>;
145
146template <typename Type>
Michael Butler4b276a72020-08-06 23:22:35 -0700147nn::GeneralResult<hidl_vec<convertOutput<Type>>> convert(const std::vector<Type>& arguments) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800148 hidl_vec<convertOutput<Type>> halObject(arguments.size());
149 for (size_t i = 0; i < arguments.size(); ++i) {
150 halObject[i] = NN_TRY(convert(arguments[i]));
151 }
152 return halObject;
153}
154
155} // anonymous namespace
156
Michael Butler4b276a72020-08-06 23:22:35 -0700157nn::GeneralResult<OperationType> convert(const nn::OperationType& operationType) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800158 return static_cast<OperationType>(operationType);
159}
160
Michael Butler4b276a72020-08-06 23:22:35 -0700161nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800162 return Capabilities{
163 .float32Performance = NN_TRY(convert(
164 capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))),
165 .quantized8Performance = NN_TRY(convert(
166 capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))),
167 .relaxedFloat32toFloat16Performance =
168 NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
169 };
170}
171
Michael Butler4b276a72020-08-06 23:22:35 -0700172nn::GeneralResult<Operation> convert(const nn::Operation& operation) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800173 return Operation{
174 .type = NN_TRY(convert(operation.type)),
175 .inputs = operation.inputs,
176 .outputs = operation.outputs,
177 };
178}
179
Michael Butler4b276a72020-08-06 23:22:35 -0700180nn::GeneralResult<Model> convert(const nn::Model& model) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800181 if (!hal::utils::hasNoPointerData(model)) {
Michael Butler4b276a72020-08-06 23:22:35 -0700182 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
183 << "Mdoel cannot be converted because it contains pointer-based memory";
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800184 }
185
186 auto operands = NN_TRY(convert(model.main.operands));
187
188 // Update number of consumers.
189 const auto numberOfConsumers =
190 hal::utils::countNumberOfConsumers(operands.size(), model.main.operations);
191 CHECK(operands.size() == numberOfConsumers.size());
192 for (size_t i = 0; i < operands.size(); ++i) {
193 operands[i].numberOfConsumers = numberOfConsumers[i];
194 }
195
196 return Model{
197 .operands = std::move(operands),
198 .operations = NN_TRY(convert(model.main.operations)),
199 .inputIndexes = model.main.inputIndexes,
200 .outputIndexes = model.main.outputIndexes,
201 .operandValues = NN_TRY(convert(model.operandValues)),
202 .pools = NN_TRY(convert(model.pools)),
203 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
204 };
205}
206
Michael Butler4b276a72020-08-06 23:22:35 -0700207nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference) {
Michael Butlerb98aa6d2020-02-22 22:37:59 -0800208 return static_cast<ExecutionPreference>(executionPreference);
209}
210
211} // namespace android::hardware::neuralnetworks::V1_1::utils