diff --git a/compiler/circle2circle/src/Circle2Circle.cpp b/compiler/circle2circle/src/Circle2Circle.cpp index 5dd6ed52edb..8757900c9af 100644 --- a/compiler/circle2circle/src/Circle2Circle.cpp +++ b/compiler/circle2circle/src/Circle2Circle.cpp @@ -184,6 +184,8 @@ int entry(int argc, char **argv) "This will convert single input Transpose to Reshape"); add_switch(arser, "--expand_broadcast_const", "This will expand broadcastable constant inputs"); add_switch(arser, "--unroll_unidirseqlstm", "Unroll UnidirectionalSequenceLSTM operator."); + add_switch(arser, "--compress_weights_huffman", + "Loseless weights compression with Huffman encoding."); add_switch(arser, "--convert_nchw_to_nhwc", "Experimental: This will convert NCHW operators to NHWC under the assumption that " "input model is NCHW."); @@ -405,6 +407,8 @@ int entry(int argc, char **argv) options->enable(Algorithms::ExpandBroadcastConst); if (arser.get("--unroll_unidirseqlstm")) options->enable(Algorithms::UnrollUnidirSeqLSTM); + if (arser.get("--compress_weights_huffman")) + options->enable(Algorithms::CompressWeightsHuffman); // NOTE Experimental options; these will be removed someday // Add experimental options here diff --git a/compiler/luci/export/src/CircleBuiltinTypesExtractor.h b/compiler/luci/export/src/CircleBuiltinTypesExtractor.h index efc2a510649..4458a1ae3b7 100644 --- a/compiler/luci/export/src/CircleBuiltinTypesExtractor.h +++ b/compiler/luci/export/src/CircleBuiltinTypesExtractor.h @@ -108,10 +108,10 @@ class BuiltinOptionsExtractor final // flatbuffers::Offset visit(luci::CircleConst *) flatbuffers::Offset visit(luci::CircleConv2D *node) { - return circle::CreateConv2DOptions(_builder, getOpPadding(node->padding()), node->stride()->w(), - node->stride()->h(), - to_circle_actfunc(node->fusedActivationFunction()), - node->dilation()->w(), node->dilation()->h()) + return circle::CreateConv2DOptions( + _builder, getOpPadding(node->padding()), node->stride()->w(), node->stride()->h(), + to_circle_actfunc(node->fusedActivationFunction()), node->dilation()->w(), + node->dilation()->h(), to_circle_weightcompressiontype(node->weightCompression())) .Union(); } flatbuffers::Offset visit(luci::CircleCos *) diff --git a/compiler/luci/export/src/CircleExporterUtils.cpp b/compiler/luci/export/src/CircleExporterUtils.cpp index 6678b0dc328..fc72f604b25 100644 --- a/compiler/luci/export/src/CircleExporterUtils.cpp +++ b/compiler/luci/export/src/CircleExporterUtils.cpp @@ -24,6 +24,19 @@ namespace luci { +circle::WeightCompressionType to_circle_weightcompressiontype(luci::WeightCompression type) +{ + switch (type) + { + case luci::WeightCompression::NONE: + return circle::WeightCompressionType_NONE; + case luci::WeightCompression::HUFFMAN: + return circle::WeightCompressionType_Huffman; + default: + INTERNAL_EXN_V("trying to convert unsupported luci::WeightCompression", + oops::to_uint32(type)); + } +} circle::ActivationFunctionType to_circle_actfunc(luci::FusedActFunc func) { diff --git a/compiler/luci/export/src/CircleExporterUtils.h b/compiler/luci/export/src/CircleExporterUtils.h index 4a4c54a695a..fd3c3203013 100644 --- a/compiler/luci/export/src/CircleExporterUtils.h +++ b/compiler/luci/export/src/CircleExporterUtils.h @@ -29,6 +29,7 @@ namespace luci { +circle::WeightCompressionType to_circle_weightcompressiontype(luci::WeightCompression type); circle::ActivationFunctionType to_circle_actfunc(luci::FusedActFunc func); circle::TensorType to_circle_tensortype(loco::DataType type); circle::MirrorPadMode to_circle_mirrorpadmode(luci::MirrorPadMode mode); diff --git a/compiler/luci/export/src/CircleTensorExporter.cpp b/compiler/luci/export/src/CircleTensorExporter.cpp index 0022a0e57e8..91df5ff1d2e 100644 --- a/compiler/luci/export/src/CircleTensorExporter.cpp +++ b/compiler/luci/export/src/CircleTensorExporter.cpp @@ -559,6 +559,8 @@ bool has_same_values(luci::CircleConst *lhs, luci::CircleConst *rhs) return has_same_elements(lhs, rhs); case loco::DataType::S8: + if (lhs->size() != rhs->size()) + return false; return has_same_elements(lhs, rhs); case loco::DataType::S16: @@ -574,6 +576,8 @@ bool has_same_values(luci::CircleConst *lhs, luci::CircleConst *rhs) return has_same_elements(lhs, rhs); case loco::DataType::U8: + if (lhs->size() != rhs->size()) + return false; return has_same_elements(lhs, rhs); case loco::DataType::BOOL: diff --git a/compiler/luci/import/include/luci/Import/CircleImporterUtils.h b/compiler/luci/import/include/luci/Import/CircleImporterUtils.h new file mode 100644 index 00000000000..19e9be051b5 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/CircleImporterUtils.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * 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. + */ + +#ifndef __CIRCLE_IMPORTER_UTILS_H__ +#define __CIRCLE_IMPORTER_UTILS_H__ + +#include + +#include + +#include + +namespace luci +{ +luci::WeightCompression from_circle_weightcompressiontype(circle::WeightCompressionType type); + +} // namespace luci + +#endif // __CIRCLE_IMPORTER_UTILS_H__ diff --git a/compiler/luci/import/src/CircleImporterUtils.cpp b/compiler/luci/import/src/CircleImporterUtils.cpp new file mode 100644 index 00000000000..a0425b4c9c3 --- /dev/null +++ b/compiler/luci/import/src/CircleImporterUtils.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * 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 "luci/Import/CircleImporterUtils.h" + +#include + +namespace luci +{ +luci::WeightCompression from_circle_weightcompressiontype(circle::WeightCompressionType type) +{ + switch (type) + { + case circle::WeightCompressionType_NONE: + return luci::WeightCompression::NONE; + case circle::WeightCompressionType_Huffman: + return luci::WeightCompression::HUFFMAN; + default: + INTERNAL_EXN_V("trying to convert unsupported luci::WeightCompression", + oops::to_uint32(type)); + } +} +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleConv2D.cpp b/compiler/luci/import/src/Nodes/CircleConv2D.cpp index 8cbecdc003b..d947fddc4f3 100644 --- a/compiler/luci/import/src/Nodes/CircleConv2D.cpp +++ b/compiler/luci/import/src/Nodes/CircleConv2D.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ +#include "luci/Import/CircleImporterUtils.h" #include "luci/Import/Nodes/CircleConv2D.h" #include - #include #include @@ -49,6 +49,7 @@ CircleNode *CircleConv2DGraphBuilder::build_node(const circle::OperatorT &op, node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); node->dilation()->w(options->dilation_w_factor); node->dilation()->h(options->dilation_h_factor); + node->weightCompression(from_circle_weightcompressiontype(options->weight_compression_type)); return node; } diff --git a/compiler/luci/lang/include/luci/IR/AttrWeightCompression.h b/compiler/luci/lang/include/luci/IR/AttrWeightCompression.h new file mode 100644 index 00000000000..418ba3f07ac --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/AttrWeightCompression.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * 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. + */ + +#ifndef __LUCI_IR_ATTRWEIGHTCOMPRESSION_H__ +#define __LUCI_IR_ATTRWEIGHTCOMPRESSION_H__ + +namespace luci +{ + +enum class WeightCompression +{ + UNDEFINED, // This is not defined by TFLite or Circle. This was added to + // prevent programming error. + NONE, + HUFFMAN +}; + +} // namespace luci + +#endif // __LUCI_IR_ATTRWEIGHTCOMPRESSION_H__ diff --git a/compiler/luci/lang/include/luci/IR/CircleNodeMixins.h b/compiler/luci/lang/include/luci/IR/CircleNodeMixins.h index 158d65d902f..e8fc1b2446a 100644 --- a/compiler/luci/lang/include/luci/IR/CircleNodeMixins.h +++ b/compiler/luci/lang/include/luci/IR/CircleNodeMixins.h @@ -18,6 +18,7 @@ #define __LUCI_IR_CIRCLE_NODE_MIXINS_H__ #include "luci/IR/AttrFusedActFunc.h" +#include "luci/IR/AttrWeightCompression.h" #include #include @@ -31,11 +32,28 @@ namespace luci enum class CircleNodeTrait { FusedActFunc, - Bias + Bias, + WeightCompression }; template class CircleNodeMixin; +template <> class CircleNodeMixin +{ +public: + CircleNodeMixin() = default; + +public: + WeightCompression weightCompression() const { return _weight_compression; } + void weightCompression(WeightCompression weight_compression) + { + _weight_compression = weight_compression; + } + +private: + WeightCompression _weight_compression = WeightCompression::UNDEFINED; +}; + template <> class CircleNodeMixin { public: diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h index 3e9a274e0cd..0d45c74b735 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h @@ -17,6 +17,7 @@ #ifndef __LUCI_IR_CIRCLECONST_H__ #define __LUCI_IR_CIRCLECONST_H__ +#include "luci/IR/AttrWeightCompression.h" #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" @@ -34,6 +35,9 @@ namespace luci class CircleConst final : public FixedArityNode<0, CircleNodeImpl> { public: + template WeightCompression compression(void) const; + template void compression(WeightCompression c); + template uint32_t size(void) const; template void size(uint32_t size); template const typename loco::DataTypeImpl
::Type &at(uint32_t n) const; @@ -46,6 +50,7 @@ class CircleConst final : public FixedArityNode<0, CircleNodeImpl _data; // TODO use _data for STRING and remove _strings std::vector _strings; // for STRING type + WeightCompression _compression{WeightCompression::NONE}; }; } // namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h index 7c390940e73..f00270427e1 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h @@ -34,7 +34,8 @@ namespace luci */ class CircleConv2D final : public FixedArityNode<3, CircleNodeImpl>, public CircleNodeMixin, - public CircleNodeMixin + public CircleNodeMixin, + public CircleNodeMixin { public: loco::Node *input(void) const { return at(0)->node(); } diff --git a/compiler/luci/lang/src/Nodes/CircleConst.cpp b/compiler/luci/lang/src/Nodes/CircleConst.cpp index c17a4e2c36d..8d4d9d5a604 100644 --- a/compiler/luci/lang/src/Nodes/CircleConst.cpp +++ b/compiler/luci/lang/src/Nodes/CircleConst.cpp @@ -20,6 +20,17 @@ namespace luci { +template WeightCompression CircleConst::compression(void) const +{ + assert(dtype() == DT); + return _compression; +} + +template void CircleConst::compression(luci::WeightCompression c) +{ + assert(dtype() == DT); + _compression = c; +} template uint32_t CircleConst::size(void) const { @@ -63,6 +74,8 @@ template typename loco::DataTypeImpl
::Type &CircleConst: } #define INSTANTIATE(DT) \ + template WeightCompression CircleConst::compression
(void) const; \ + template void CircleConst::compression
(WeightCompression); \ template uint32_t CircleConst::size
(void) const; \ template void CircleConst::size
(uint32_t); \ template const typename loco::DataTypeImpl
::Type &CircleConst::at
(uint32_t) const; \ diff --git a/compiler/luci/pass/include/luci/CircleOptimizer.h b/compiler/luci/pass/include/luci/CircleOptimizer.h index 01b43a72844..261c8825753 100644 --- a/compiler/luci/pass/include/luci/CircleOptimizer.h +++ b/compiler/luci/pass/include/luci/CircleOptimizer.h @@ -109,6 +109,7 @@ class CircleOptimizer final UnrollUnidirSeqLSTM, XpSepActFromTransposeConv, RemoveGatherGuard, + CompressWeightsHuffman }; enum AlgorithmParameters diff --git a/compiler/luci/pass/include/luci/Pass/CompressWeightsPass.h b/compiler/luci/pass/include/luci/Pass/CompressWeightsPass.h new file mode 100644 index 00000000000..f9f97791914 --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/CompressWeightsPass.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * 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. + */ + +#ifndef __LUCI_COMPRESS_WEIGHTS_PASS_H__ +#define __LUCI_COMPRESS_WEIGHTS_PASS_H__ + +#include + +namespace luci +{ + +/** + * @brief Class to generate FC/CONV with compressed weights + * + * To see the target Op pattern, please visit implementation. + */ +struct CompressWeightsPass final : public logo::Pass +{ + const char *name(void) const final { return "luci::CompressWeightsPass"; } + + bool run(loco::Graph *g) final; +}; + +} // namespace luci + +#endif // __LUCI_COMPRESS_WEIGHTS_PASS_H__ diff --git a/compiler/luci/pass/src/CircleOptimizer.cpp b/compiler/luci/pass/src/CircleOptimizer.cpp index 3c94311c8d5..d56276472cd 100644 --- a/compiler/luci/pass/src/CircleOptimizer.cpp +++ b/compiler/luci/pass/src/CircleOptimizer.cpp @@ -92,6 +92,7 @@ #include "luci/Pass/DecomposeSoftmaxPass.h" #include "luci/Pass/UnrollUnidirectionalSequenceLSTMPass.h" #include "luci/Pass/XpSepActFromTransposeConvPass.h" +#include "luci/Pass/CompressWeightsPass.h" // TODO add more passes #include "luci/Pass/CircleShapeInferencePass.h" @@ -534,7 +535,10 @@ void CircleOptimizer::optimize(loco::Graph *g) const { phase.emplace_back(std::make_unique()); } - + if (_options->query(Options::Algorithm::CompressWeightsHuffman)) + { + phase.emplace_back(std::make_unique()); + } // NOTE Experimental options; these will be removed someday // Add experimental options here if (_options->query(Options::Algorithm::XpSepActFromTransposeConv)) diff --git a/compiler/luci/pass/src/CompressWeightsPass.cpp b/compiler/luci/pass/src/CompressWeightsPass.cpp new file mode 100644 index 00000000000..d2a2822373f --- /dev/null +++ b/compiler/luci/pass/src/CompressWeightsPass.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * 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 "luci/Pass/CompressWeightsPass.h" +#include "helpers/HuffmanEncoder.h" +#include "helpers/NodeFiller.h" + +#include +#include + +#include +#include + +namespace +{ + +template class TypeSelector; + +template <> class TypeSelector +{ +public: + using Type = uint8_t; +}; +template <> class TypeSelector +{ +public: + using Type = int8_t; +}; + +template bool compress_weights_huffman_conv2d(luci::CircleConv2D *conv2d) +{ + using T = typename TypeSelector
::Type; + assert(conv2d); + + auto weights = loco::must_cast(conv2d->filter()); + if (weights->compression
() != luci::WeightCompression::NONE) + return false; + + luci::huffman::HuffmanEncoder encoder; + auto new_weights = luci::clone(weights); + std::vector tmp_buf{}; + for (size_t i = 0; i < weights->size
(); ++i) + { + T data = weights->at
(i); + tmp_buf.push_back(data); + } + std::vector encoded = encoder.encode(tmp_buf); + new_weights->dtype(DT); + new_weights->size
(encoded.size()); + new_weights->compression
(luci::WeightCompression::HUFFMAN); + for (size_t i = 0; i < new_weights->size
(); ++i) + { + new_weights->at
(i) = encoded[i]; + } + conv2d->filter(new_weights); +// conv2d->weightCompression(luci::WeightCompression::HUFFMAN); + + return true; +} + +} // namespace + +namespace luci +{ + +bool CompressWeightsPass::run(loco::Graph *g) +{ + bool changed = false; + + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + auto conv2d = dynamic_cast(node); + if (not conv2d) + continue; + + auto filter = loco::must_cast(conv2d->filter()); + + if (filter->dtype() == loco::DataType::S8) + { + if (compress_weights_huffman_conv2d(conv2d)) + changed = true; + } + else if (filter->dtype() == loco::DataType::U8) + { + if (compress_weights_huffman_conv2d(conv2d)) + changed = true; + } + } + + return changed; +} + +} // namespace luci diff --git a/compiler/luci/pass/src/helpers/HuffmanEncoder.h b/compiler/luci/pass/src/helpers/HuffmanEncoder.h new file mode 100644 index 00000000000..4c2b09d8a5b --- /dev/null +++ b/compiler/luci/pass/src/helpers/HuffmanEncoder.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * 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. + */ + +#ifndef __LUCI_PASS_HELPERS_HUFFMAN_ENCODER_H__ +#define __LUCI_PASS_HELPERS_HUFFMAN_ENCODER_H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace luci +{ + +namespace huffman +{ + +// Node of prefix tree +template struct Node +{ + std::shared_ptr> p_left; + std::shared_ptr> p_right; + T data; + unsigned int freq; +}; + +// Compare functor for priority queue +template struct CompareNodes +{ + bool operator()(std::shared_ptr> l, std::shared_ptr> r) + { + return l->freq > r->freq; + } +}; + +template class HuffmanEncoder +{ +private: + std::unordered_map _huffman_table; + +private: + std::shared_ptr> allocateNode(T data, unsigned int freq, std::shared_ptr> p_left, + std::shared_ptr> p_right) + { + std::shared_ptr> node = std::make_unique>(); + node->data = data; + node->freq = freq; + node->p_left = p_left; + node->p_right = p_right; + return node; + } + + std::unordered_map calculateFrequencyMap(const std::vector &input) + { + std::unordered_map out_map; + for (auto &item : input) + out_map[item] = out_map.find(item) != out_map.end() ? out_map[item] + 1 : 1; + + return out_map; + } + + std::string exportHuffmanTreeToString(std::shared_ptr> node) + { + if (node == nullptr) + return ""; + + if (!node->p_left && !node->p_right) + { + return "0" + std::bitset(node->data).to_string(); + } + + std::string tmp = "1"; + tmp += exportHuffmanTreeToString(node->p_left); + tmp += exportHuffmanTreeToString(node->p_right); + return tmp; + } + + void buildHuffmanTable(std::shared_ptr> node, const std::string str = "") + { + if (node == nullptr) + return; + + if (!node->p_left && !node->p_right) + { + _huffman_table[node->data] = str; + } + + buildHuffmanTable(node->p_left, str + "0"); + buildHuffmanTable(node->p_right, str + "1"); + } + + std::shared_ptr> buildHuffmanTree(const std::vector &input) + { + auto freq_map = calculateFrequencyMap(input); + + std::priority_queue>, std::vector>>, + CompareNodes> + pq; + + for (auto &item : freq_map) + { + pq.push(allocateNode(item.first, item.second, nullptr, nullptr)); + } + + while (pq.size() != 1) + { + std::shared_ptr> left = pq.top(); + pq.pop(); + std::shared_ptr> right = pq.top(); + pq.pop(); + + unsigned int sum = left->freq + right->freq; + pq.push(allocateNode(0, sum, left, right)); + } + + return pq.top(); + } + + struct EncodedTreeAndData + { + std::vector tree_vec{}; + std::vector data_vec{}; + }; + + std::vector packEncodedDataToArray(const std::string &tree_str, + const std::string &encoded_data) + { + std::vector arr; + const size_t kTreeSizeInBits = tree_str.size(); + const size_t kDataSizeInBits = encoded_data.size(); + + for (size_t i = 0; i < sizeof(size_t); ++i) + { + arr.push_back( + *(static_cast(static_cast(&kTreeSizeInBits)) + i)); + } + + for (size_t i = 0; i < sizeof(size_t); ++i) + { + arr.push_back( + *(static_cast(static_cast(&kDataSizeInBits)) + i)); + } + + const auto merged_str = tree_str + encoded_data; + const size_t kMergedSizeInBits = merged_str.size(); + + const auto kMergedSizeInBytes = kMergedSizeInBits % CHAR_BIT ? kMergedSizeInBits / CHAR_BIT + 1 + : kMergedSizeInBits / CHAR_BIT; + for (size_t i = 0; i < kMergedSizeInBytes; ++i) + { + const auto kNumOfBits = + kMergedSizeInBits - i * CHAR_BIT < CHAR_BIT ? kMergedSizeInBits - i * CHAR_BIT : CHAR_BIT; + + std::string tmp_str = merged_str.substr(i * CHAR_BIT, kNumOfBits); + + for (size_t i = 0; i < CHAR_BIT - kNumOfBits; ++i) + tmp_str += "0"; + + const std::bitset tmp_bitset(tmp_str); + + arr.push_back(static_cast(tmp_bitset.to_ullong())); + } + return arr; + } + +public: + // Encodes input vector of values of type T and returns encoded vector of uint8_t + std::vector encode(const std::vector &input) + { + std::shared_ptr> root = buildHuffmanTree(input); + buildHuffmanTable(root); + + std::string exported_tree = exportHuffmanTreeToString(root); + std::string str = ""; + + for (auto &item : input) + { + str += _huffman_table[item]; + } + + std::vector raw_arr = packEncodedDataToArray(exported_tree, str); + return raw_arr; + } + +public: + HuffmanEncoder() = default; +}; +} // namespace huffman +} // namespace luci +#endif // __LUCI_PASS_HELPERS_HUFFMAN_ENCODER_H__ diff --git a/res/CircleSchema/0.8/circle_schema.fbs b/res/CircleSchema/0.8/circle_schema.fbs index 460fa43ee11..922bd6cc2a7 100644 --- a/res/CircleSchema/0.8/circle_schema.fbs +++ b/res/CircleSchema/0.8/circle_schema.fbs @@ -822,6 +822,11 @@ enum ActivationFunctionType : byte { } // LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) +enum WeightCompressionType : byte { + NONE = 0, + Huffman = 1 +} +// LINT.ThenChange(//tensorflow/compiler/mlir/lite/ir/tfl_op_enums.td) table Conv2DOptions { padding:Padding; stride_w:int; @@ -831,6 +836,7 @@ table Conv2DOptions { dilation_h_factor:int = 1; // Parameters for Conv2D version 8 or above. // When set, quantized_bias_type defines the dtype for both bias and accumulator. + weight_compression_type:WeightCompressionType = NONE; quantized_bias_type: TensorType; }