diff --git a/ethosu/regor/tflite/tflite_mapping.cpp b/ethosu/regor/tflite/tflite_mapping.cpp index 769e2bbfd9169e1510c719d5dd78b60b203715b6..27c31c398f67f38dbc17454d0c54d1c786af816b 100644 --- a/ethosu/regor/tflite/tflite_mapping.cpp +++ b/ethosu/regor/tflite/tflite_mapping.cpp @@ -349,11 +349,54 @@ const std::map TfLiteMapping::_ {tflite::BuiltinOperator::HASHTABLE_IMPORT, tflite::BuiltinOptions::HashtableImportOptions}, {tflite::BuiltinOperator::HASHTABLE_SIZE, tflite::BuiltinOptions::HashtableSizeOptions}, {tflite::BuiltinOperator::REDUCE_ALL, tflite::BuiltinOptions::ReducerOptions}, - // TODO: {tflite::BuiltinOperator::CONV_3D_TRANSPOSE, tflite::BuiltinOptions::???}, + {tflite::BuiltinOperator::CONV_3D_TRANSPOSE, tflite::BuiltinOptions::Conv3DOptions}, {tflite::BuiltinOperator::VAR_HANDLE, tflite::BuiltinOptions::VarHandleOptions}, {tflite::BuiltinOperator::READ_VARIABLE, tflite::BuiltinOptions::ReadVariableOptions}, {tflite::BuiltinOperator::ASSIGN_VARIABLE, tflite::BuiltinOptions::AssignVariableOptions}, {tflite::BuiltinOperator::BROADCAST_ARGS, tflite::BuiltinOptions::NONE}, + {tflite::BuiltinOperator::RANDOM_STANDARD_NORMAL, tflite::BuiltinOptions::RandomOptions}, + {tflite::BuiltinOperator::BUCKETIZE, tflite::BuiltinOptions::BucketizeOptions}, + {tflite::BuiltinOperator::RANDOM_UNIFORM, tflite::BuiltinOptions::RandomOptions}, + {tflite::BuiltinOperator::MULTINOMIAL, tflite::BuiltinOptions::NONE}, + {tflite::BuiltinOperator::GELU, tflite::BuiltinOptions::GeluOptions}, + {tflite::BuiltinOperator::DYNAMIC_UPDATE_SLICE, tflite::BuiltinOptions::DynamicUpdateSliceOptions}, + {tflite::BuiltinOperator::RELU_0_TO_1, tflite::BuiltinOptions::NONE}, + {tflite::BuiltinOperator::UNSORTED_SEGMENT_PROD, tflite::BuiltinOptions::UnsortedSegmentProdOptions}, + {tflite::BuiltinOperator::UNSORTED_SEGMENT_MAX, tflite::BuiltinOptions::UnsortedSegmentMaxOptions}, + {tflite::BuiltinOperator::UNSORTED_SEGMENT_SUM, tflite::BuiltinOptions::UnsortedSegmentSumOptions}, + {tflite::BuiltinOperator::ATAN2, tflite::BuiltinOptions::ATan2Options}, + {tflite::BuiltinOperator::UNSORTED_SEGMENT_MIN, tflite::BuiltinOptions::UnsortedSegmentMinOptions}, + {tflite::BuiltinOperator::SIGN, tflite::BuiltinOptions::SignOptions}, + {tflite::BuiltinOperator::BITCAST, tflite::BuiltinOptions::BitcastOptions}, + {tflite::BuiltinOperator::BITWISE_XOR, tflite::BuiltinOptions::BitwiseXorOptions}, + {tflite::BuiltinOperator::RIGHT_SHIFT, tflite::BuiltinOptions::RightShiftOptions}, + // clang-format on +}; + +const std::map TfLiteMapping::_builtinOperatorToBuiltinOptions2 = { + // clang-format off + {tflite::BuiltinOperator::STABLEHLO_CONCATENATE, tflite::BuiltinOptions2::StablehloConcatenateOptions}, + {tflite::BuiltinOperator::STABLEHLO_BROADCAST_IN_DIM, tflite::BuiltinOptions2::StablehloBroadcastInDimOptions}, + {tflite::BuiltinOperator::STABLEHLO_CONVOLUTION, tflite::BuiltinOptions2::StablehloConvolutionOptions}, + {tflite::BuiltinOperator::STABLEHLO_SLICE, tflite::BuiltinOptions2::StablehloSliceOptions}, + {tflite::BuiltinOperator::STABLEHLO_CUSTOM_CALL, tflite::BuiltinOptions2::StablehloCustomCallOptions}, + {tflite::BuiltinOperator::STABLEHLO_REDUCE, tflite::BuiltinOptions2::StablehloReduceOptions}, + {tflite::BuiltinOperator::STABLEHLO_SCATTER, tflite::BuiltinOptions2::StablehloScatterOptions}, + {tflite::BuiltinOperator::STABLEHLO_COMPARE, tflite::BuiltinOptions2::StablehloCompareOptions}, + {tflite::BuiltinOperator::STABLEHLO_DYNAMIC_SLICE, tflite::BuiltinOptions2::StablehloDynamicSliceOptions}, + {tflite::BuiltinOperator::STABLEHLO_PAD, tflite::BuiltinOptions2::StablehloPadOptions}, + {tflite::BuiltinOperator::STABLEHLO_IOTA, tflite::BuiltinOptions2::StablehloIotaOptions}, + {tflite::BuiltinOperator::STABLEHLO_DOT_GENERAL, tflite::BuiltinOptions2::StablehloDotGeneralOptions}, + {tflite::BuiltinOperator::STABLEHLO_REDUCE_WINDOW, tflite::BuiltinOptions2::StablehloReduceWindowOptions}, + {tflite::BuiltinOperator::STABLEHLO_SORT, tflite::BuiltinOptions2::StablehloSortOptions}, + {tflite::BuiltinOperator::STABLEHLO_WHILE, tflite::BuiltinOptions2::StablehloWhileOptions}, + {tflite::BuiltinOperator::STABLEHLO_GATHER, tflite::BuiltinOptions2::StablehloGatherOptions}, + {tflite::BuiltinOperator::STABLEHLO_TRANSPOSE, tflite::BuiltinOptions2::StablehloTransposeOptions}, + {tflite::BuiltinOperator::DILATE, tflite::BuiltinOptions2::DilateOptions}, + {tflite::BuiltinOperator::STABLEHLO_RNG_BIT_GENERATOR, tflite::BuiltinOptions2::StablehloRngBitGeneratorOptions}, + {tflite::BuiltinOperator::REDUCE_WINDOW, tflite::BuiltinOptions2::ReduceWindowOptions}, + {tflite::BuiltinOperator::STABLEHLO_COMPOSITE, tflite::BuiltinOptions2::StableHLOCompositeOptions}, + {tflite::BuiltinOperator::STABLEHLO_SHIFT_LEFT, tflite::BuiltinOptions2::StablehloShiftLeftOptions}, // clang-format on }; @@ -613,8 +656,8 @@ bool TfLiteMapping::CanFuseActivationFunction(const Operation *operation) return false; // Only fuse operators which came in fused } - const auto type = TfLiteMapping::OpTypeToBuiltinOptions(operation->Type()); const tflite::Operator *const passthrough = static_cast(operation->Passthrough()); + const tflite::BuiltinOptions type = passthrough->builtin_options_type(); tflite::ActivationFunctionType activation; if ( type == tflite::BuiltinOptions::Conv2DOptions ) @@ -689,6 +732,10 @@ bool TfLiteMapping::CanFuseActivationFunction(const Operation *operation) { activation = GetBuiltinFaf(passthrough); } + else if ( type == tflite::BuiltinOptions::TransposeConvOptions ) + { + activation = GetBuiltinFaf(passthrough); + } else { return false; // Operator type does not support fused activations diff --git a/ethosu/regor/tflite/tflite_mapping.hpp b/ethosu/regor/tflite/tflite_mapping.hpp index 7e6f0aee0ae92c3201f9dc5529536872d7d566a1..7e040cd8d10e6e6b102ce6ae27c5bdb4bda2fb35 100644 --- a/ethosu/regor/tflite/tflite_mapping.hpp +++ b/ethosu/regor/tflite/tflite_mapping.hpp @@ -1,5 +1,5 @@ // -// SPDX-FileCopyrightText: Copyright 2021, 2023-2024 Arm Limited and/or its affiliates +// SPDX-FileCopyrightText: Copyright 2021, 2023-2025 Arm Limited and/or its affiliates // // SPDX-License-Identifier: Apache-2.0 // @@ -54,6 +54,26 @@ public: static std::string BuiltinOperatorToString(tflite::BuiltinOperator &type) { return EnumNameBuiltinOperator(type); } + static tflite::BuiltinOptions BuiltinOperatorToBuiltinOptions(tflite::BuiltinOperator op) + { + auto it1 = _builtinOperatorToBuiltinOptions.find(op); + if ( it1 == _builtinOperatorToBuiltinOptions.end() ) + { + return tflite::BuiltinOptions::NONE; + } + return it1->second; + } + + static tflite::BuiltinOptions2 BuiltinOperatorToBuiltinOptions2(tflite::BuiltinOperator op) + { + auto it1 = _builtinOperatorToBuiltinOptions2.find(op); + if ( it1 == _builtinOperatorToBuiltinOptions2.end() ) + { + return tflite::BuiltinOptions2::NONE; + } + return it1->second; + } + // // Conversions from Regor types to TensorFlow Lite types // @@ -78,20 +98,6 @@ public: return type == OpType::CustomNpuOp ? tflite::BuiltinOperator::CUSTOM : _opTypeToBuiltinOperator.at(type); } - static tflite::BuiltinOptions OpTypeToBuiltinOptions(OpType type) - { - auto it1 = _opTypeToBuiltinOperator.find(type); - if ( it1 == _opTypeToBuiltinOperator.end() ) - { - return tflite::BuiltinOptions::NONE; - } - auto it2 = _builtinOperatorToBuiltinOptions.find(it1->second); - if ( it2 == _builtinOperatorToBuiltinOptions.end() ) - { - return tflite::BuiltinOptions::NONE; - } - return it2->second; - } class InputTensorIndices; // Usage: for (const auto& map_entry : InputTensorIndices(op_type)) {} @@ -117,6 +123,7 @@ private: // Mapping from TensorFlow Lite operator type to TensorFlow Lite options type is N:1 static const std::map _builtinOperatorToBuiltinOptions; + static const std::map _builtinOperatorToBuiltinOptions2; // The number of input tensors to a TensorFlow Lite operator depends on the operator type, // as does the order in which the different kinds of input tensor are listed. diff --git a/ethosu/regor/tflite/tflite_reader.cpp b/ethosu/regor/tflite/tflite_reader.cpp index 2228ef4d0a770f164e179d4e0c4eac8f15410421..9710d50a2bfbd6b4268316b12307fa8d9020258e 100644 --- a/ethosu/regor/tflite/tflite_reader.cpp +++ b/ethosu/regor/tflite/tflite_reader.cpp @@ -105,12 +105,15 @@ const tflite::Model *TfLiteReader::LoadModel(const void *input, size_t size) } void TfLiteReader::LoadGraphs(const uint8_t *input, const tflite::Model *model, - std::vector> &graphs, OptimiserDatabase *optDb) + std::vector> &graphs, OptimiserDatabase *optDb, bool skipSemanticsCheck) { assert(model); - auto semanticsChecker = tflite::TFLiteModelSemantics(model); - semanticsChecker.Check(); + if ( !skipSemanticsCheck ) + { + auto semanticsChecker = tflite::TFLiteModelSemantics(model); + semanticsChecker.Check(); + } std::unordered_map tensorQuantization{}; std::vector opcodes; @@ -342,9 +345,10 @@ void TfLiteReader::LoadGraphs(const uint8_t *input, const tflite::Model *model, } } -void TfLiteReader::LoadGraphs(const void *input, size_t size, std::vector> &graphs, OptimiserDatabase *optDb) +void TfLiteReader::LoadGraphs(const void *input, size_t size, std::vector> &graphs, + OptimiserDatabase *optDb, bool skipSemanticsCheck) { - LoadGraphs(reinterpret_cast(input), LoadModel(input, size), graphs, optDb); + LoadGraphs(reinterpret_cast(input), LoadModel(input, size), graphs, optDb, skipSemanticsCheck); } std::shared_ptr TfLiteReader::ParseTensor(const tflite::Tensor *tflite_tensor, std::shared_ptr &buffer, diff --git a/ethosu/regor/tflite/tflite_reader.hpp b/ethosu/regor/tflite/tflite_reader.hpp index 1104c2e985fcaa2acc374f2b5df28b4a6b9f84e2..81ae0c891737f7dd6887c5e0f7a266ea8e868c1c 100644 --- a/ethosu/regor/tflite/tflite_reader.hpp +++ b/ethosu/regor/tflite/tflite_reader.hpp @@ -39,11 +39,11 @@ public: TfLiteReader() {} static void LoadGraphs(const void *input, size_t size, std::vector> &graphs, - OptimiserDatabase *optDb); // From buffer + OptimiserDatabase *optDb, bool skipSemanticsCheck = false); // From buffer private: static void LoadGraphs(const uint8_t *input, const tflite::Model *model, std::vector> &graphs, - OptimiserDatabase *optDb); // From model + OptimiserDatabase *optDb, bool skipSemanticsCheck = false); // From model static const tflite::Model *LoadModel(const void *input, size_t size); static std::shared_ptr ParseTensor(const tflite::Tensor *tflite_tensor, std::shared_ptr &buffer, std::unordered_map &tensorQuantization); diff --git a/ethosu/regor/tflite/tflite_writer.cpp b/ethosu/regor/tflite/tflite_writer.cpp index ca707e7a0bc564e483188ada4628e11d2a27fa8c..b01ec963649186c30fb2c17870c87602a8615352 100644 --- a/ethosu/regor/tflite/tflite_writer.cpp +++ b/ethosu/regor/tflite/tflite_writer.cpp @@ -124,6 +124,7 @@ std::unique_ptr TfLiteWriter::SerialiseImpl(const std::vectorType(); tflite::BuiltinOperator builtin_code; tflite::BuiltinOptions builtin_options_type; + tflite::BuiltinOptions2 builtin_options_2_type; if ( type == OpType::Passthrough ) { assert(tflite_model); @@ -137,11 +138,13 @@ std::unique_ptr TfLiteWriter::SerialiseImpl(const std::vector(deprecated_builtin_code); } builtin_options_type = tflite_operator->builtin_options_type(); + builtin_options_2_type = tflite_operator->builtin_options_2_type(); } else { builtin_code = TfLiteMapping::OpTypeToBuiltinOperator(type); - builtin_options_type = TfLiteMapping::OpTypeToBuiltinOptions(type); + builtin_options_type = TfLiteMapping::BuiltinOperatorToBuiltinOptions(builtin_code); + builtin_options_2_type = TfLiteMapping::BuiltinOperatorToBuiltinOptions2(builtin_code); } // Set deprecated_builtin_code for backwards compatibility @@ -203,6 +206,8 @@ std::unique_ptr TfLiteWriter::SerialiseImpl(const std::vector> custom_options = 0; flatbuffers::Offset> mvi = 0; // mutating_variable_inputs flatbuffers::Offset> intermediates = 0; + uint64_t large_custom_options_offset = 0; + uint64_t large_custom_options_size = 0; if ( type == OpType::CustomNpuOp ) { @@ -230,9 +235,11 @@ std::unique_ptr TfLiteWriter::SerialiseImpl(const std::vector(inputs); auto serialised_outputs = _flatbuffer.CreateVector(outputs); auto serialised_options = SerialiseOptions(operation, type); + auto serialised_options2 = SerialiseOptions2(operation, type); _serialised_operations.push_back(tflite::CreateOperator(_flatbuffer, opcode_index, serialised_inputs, serialised_outputs, - builtin_options_type, serialised_options, custom_options, custom_options_format, mvi, intermediates)); + builtin_options_type, serialised_options, custom_options, custom_options_format, mvi, intermediates, + large_custom_options_offset, large_custom_options_size, builtin_options_2_type, serialised_options2)); } std::vector inputs, outputs; @@ -256,7 +263,10 @@ std::unique_ptr TfLiteWriter::SerialiseImpl(const std::vector TfLiteWriter::SerialiseOptions(const Operation *operat return offset; } +flatbuffers::Offset TfLiteWriter::SerialiseOptions2(const Operation *operation, OpType opType) +{ + if ( opType == OpType::CustomNpuOp ) + { + return 0; + } + + flatbuffers::Offset offset = 0; + const tflite::Operator *const passthrough = static_cast(operation->Passthrough()); + assert(passthrough); + const auto type = passthrough->builtin_options_2_type(); + + switch ( type ) + { + case tflite::BuiltinOptions2::NONE: + break; + default: + break; + } + + return offset; +} + flatbuffers::Offset TfLiteWriter::SerialiseTensorAddresses(int subgraphs) { const int32_t version = 0; diff --git a/ethosu/regor/tflite/tflite_writer.hpp b/ethosu/regor/tflite/tflite_writer.hpp index f0e9fd0ceb605b72fa4935bb8607dd48be550740..40fe51cd3a4ed12f21d90fa36b4ccafb4944afee 100644 --- a/ethosu/regor/tflite/tflite_writer.hpp +++ b/ethosu/regor/tflite/tflite_writer.hpp @@ -39,8 +39,8 @@ namespace regor class TfLiteWriter { public: - TfLiteWriter(size_t fbSizeCap = size_t{1U << 31}) : - _flatbuffer(flatbuffers::FlatBufferBuilder()), _fbSizeCap(fbSizeCap) + TfLiteWriter(size_t fbSizeCap = size_t{1U << 31}, bool skipOfflineMemoryAllocation = false) : + _flatbuffer(flatbuffers::FlatBufferBuilder()), _fbSizeCap(fbSizeCap), _skipOfflineMemoryAllocation(skipOfflineMemoryAllocation) { } @@ -113,6 +113,7 @@ private: flatbuffers::Offset SerialiseTensor(const Tensor *tensor, const Graph &graph); flatbuffers::Offset SerialiseOptions(const Operation *operation, OpType type); + flatbuffers::Offset SerialiseOptions2(const Operation *operation, OpType type); flatbuffers::Offset SerialiseTensorAddresses(int subgraphs); void SerialiseTensorBuffer(const Tensor *tensor); @@ -233,6 +234,8 @@ private: std::vector _offset_buffers; bool _useBufferOffset = false; const size_t _fbSizeCap; + const bool _skipOfflineMemoryAllocation; // Skip writing the OfflineMemoryAllocation TFLite metadata. The purpose + // of this is primarily for unit testing. static constexpr size_t BUFFER_ALIGNMENT = 16ULL;