| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "Converter.h" |
| |
| #include <android-base/logging.h> |
| |
| #include <algorithm> |
| #include <random> |
| #include <utility> |
| #include <vector> |
| |
| #include "Utils.h" |
| |
| namespace android::nn::fuzz { |
| namespace { |
| |
| using namespace test_helper; |
| using namespace android_nn_fuzz; |
| |
| constexpr uint32_t kMaxSize = 65536; |
| |
| TestOperandType convert(OperandType type) { |
| return static_cast<TestOperandType>(type); |
| } |
| |
| TestOperationType convert(OperationType type) { |
| return static_cast<TestOperationType>(type); |
| } |
| |
| TestOperandLifeTime convert(OperandLifeTime lifetime) { |
| return static_cast<TestOperandLifeTime>(lifetime); |
| } |
| |
| std::vector<float> convert(const Scales& scales) { |
| const auto& repeatedScale = scales.scale(); |
| return std::vector<float>(repeatedScale.begin(), repeatedScale.end()); |
| } |
| |
| TestSymmPerChannelQuantParams convert(const SymmPerChannelQuantParams& params) { |
| std::vector<float> scales = convert(params.scales()); |
| const uint32_t channelDim = params.channel_dim(); |
| return {.scales = std::move(scales), .channelDim = channelDim}; |
| } |
| |
| std::vector<uint32_t> convert(const Dimensions& dimensions) { |
| const auto& repeatedDimension = dimensions.dimension(); |
| return std::vector<uint32_t>(repeatedDimension.begin(), repeatedDimension.end()); |
| } |
| |
| TestBuffer convert(size_t size, const Buffer& buffer) { |
| if (size == 0) { |
| return TestBuffer(); |
| } |
| const uint32_t randomSeed = buffer.random_seed(); |
| std::default_random_engine generator{randomSeed}; |
| return TestBuffer::createRandom(size % kMaxSize, &generator); |
| } |
| |
| TestOperand convert(const Operand& operand) { |
| const TestOperandType type = convert(operand.type()); |
| std::vector<uint32_t> dimensions = convert(operand.dimensions()); |
| const float scale = operand.scale(); |
| const int32_t zeroPoint = operand.zero_point(); |
| const TestOperandLifeTime lifetime = convert(operand.lifetime()); |
| auto channelQuant = convert(operand.channel_quant()); |
| |
| const bool isIgnored = false; |
| const auto halType = static_cast<hal::OperandType>(type); |
| const bool willOverflow = nonExtensionOperandSizeOfDataOverflowsUInt32(halType, dimensions); |
| const bool makeEmpty = (lifetime == TestOperandLifeTime::NO_VALUE || |
| lifetime == TestOperandLifeTime::TEMPORARY_VARIABLE || willOverflow); |
| const size_t bufferSize = makeEmpty ? 0 : nonExtensionOperandSizeOfData(halType, dimensions); |
| TestBuffer data = convert(bufferSize, operand.data()); |
| |
| return {.type = type, |
| .dimensions = std::move(dimensions), |
| .numberOfConsumers = 0, |
| .scale = scale, |
| .zeroPoint = zeroPoint, |
| .lifetime = lifetime, |
| .channelQuant = std::move(channelQuant), |
| .isIgnored = isIgnored, |
| .data = std::move(data)}; |
| } |
| |
| std::vector<TestOperand> convert(const Operands& operands) { |
| std::vector<TestOperand> testOperands; |
| testOperands.reserve(operands.operand_size()); |
| const auto& repeatedOperand = operands.operand(); |
| std::transform(repeatedOperand.begin(), repeatedOperand.end(), std::back_inserter(testOperands), |
| [](const auto& operand) { return convert(operand); }); |
| return testOperands; |
| } |
| |
| std::vector<uint32_t> convert(const Indexes& indexes) { |
| const auto& repeatedIndex = indexes.index(); |
| return std::vector<uint32_t>(repeatedIndex.begin(), repeatedIndex.end()); |
| } |
| |
| TestOperation convert(const Operation& operation) { |
| const TestOperationType type = convert(operation.type()); |
| std::vector<uint32_t> inputs = convert(operation.inputs()); |
| std::vector<uint32_t> outputs = convert(operation.outputs()); |
| return {.type = type, .inputs = std::move(inputs), .outputs = std::move(outputs)}; |
| } |
| |
| std::vector<TestOperation> convert(const Operations& operations) { |
| std::vector<TestOperation> testOperations; |
| testOperations.reserve(operations.operation_size()); |
| const auto& repeatedOperation = operations.operation(); |
| std::transform(repeatedOperation.begin(), repeatedOperation.end(), |
| std::back_inserter(testOperations), |
| [](const auto& operation) { return convert(operation); }); |
| return testOperations; |
| } |
| |
| void calculateNumberOfConsumers(const std::vector<TestOperation>& operations, |
| std::vector<TestOperand>* operands) { |
| CHECK(operands != nullptr); |
| const auto addConsumer = [operands](uint32_t operand) { |
| if (operand < operands->size()) { |
| operands->at(operand).numberOfConsumers++; |
| } |
| }; |
| const auto addAllConsumers = [&addConsumer](const TestOperation& operation) { |
| std::for_each(operation.inputs.begin(), operation.inputs.end(), addConsumer); |
| }; |
| std::for_each(operations.begin(), operations.end(), addAllConsumers); |
| } |
| |
| TestModel convert(const Model& model) { |
| std::vector<TestOperand> operands = convert(model.operands()); |
| std::vector<TestOperation> operations = convert(model.operations()); |
| std::vector<uint32_t> inputIndexes = convert(model.input_indexes()); |
| std::vector<uint32_t> outputIndexes = convert(model.output_indexes()); |
| const bool isRelaxed = model.is_relaxed(); |
| |
| // Calculate number of consumers. |
| calculateNumberOfConsumers(operations, &operands); |
| |
| return {.main = {.operands = std::move(operands), |
| .operations = std::move(operations), |
| .inputIndexes = std::move(inputIndexes), |
| .outputIndexes = std::move(outputIndexes)}, |
| .isRelaxed = isRelaxed}; |
| } |
| |
| } // anonymous namespace |
| |
| TestModel convertToTestModel(const Test& model) { |
| return convert(model.model()); |
| } |
| |
| } // namespace android::nn::fuzz |