summaryrefslogtreecommitdiff
path: root/compiler/luci/pass/src/FoldDensifyPass.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/luci/pass/src/FoldDensifyPass.cpp')
-rw-r--r--compiler/luci/pass/src/FoldDensifyPass.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/compiler/luci/pass/src/FoldDensifyPass.cpp b/compiler/luci/pass/src/FoldDensifyPass.cpp
new file mode 100644
index 000000000..5ddc743e5
--- /dev/null
+++ b/compiler/luci/pass/src/FoldDensifyPass.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2020 The TensorFlow Authors. 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/FoldDensifyPass.h"
+#include "helpers/SparsityFormatConverter.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/Profile/CircleNodeOrigin.h>
+
+#include <cassert>
+#include <vector>
+
+namespace
+{
+
+bool is_foldable_const(luci::CircleConst *node)
+{
+ if (node->sparsityparam() == nullptr)
+ return false;
+
+ if (node->dtype() == loco::DataType::FLOAT32)
+ return true;
+ if (node->dtype() == loco::DataType::FLOAT16)
+ return true;
+
+ return false;
+}
+
+luci::CircleConst *densified_const_node(luci::CircleConst *const_node)
+{
+ assert(const_node->sparsityparam());
+
+ auto name = const_node->name();
+ assert(name.length() > 0);
+ auto g = const_node->graph();
+ auto new_const_node = g->nodes()->create<luci::CircleConst>();
+
+ new_const_node->dtype(const_node->dtype());
+ new_const_node->rank(const_node->rank());
+
+ uint32_t dim_size = 1;
+ std::vector<int> dense_shape;
+ for (uint32_t i = 0; i < new_const_node->rank(); ++i)
+ {
+ assert(const_node->dim(i).known());
+ new_const_node->dim(i) = const_node->dim(i);
+
+ uint32_t value = const_node->dim(i).value();
+ dim_size *= value;
+ dense_shape.emplace_back(static_cast<int32_t>(value));
+ }
+
+ if (const_node->dtype() == loco::DataType::FLOAT32)
+ new_const_node->size<loco::DataType::FLOAT32>(dim_size);
+ else
+ {
+ assert(const_node->dtype() == loco::DataType::FLOAT16);
+ new_const_node->size<loco::DataType::FLOAT16>(dim_size);
+ }
+
+ new_const_node->shape_status(luci::ShapeStatus::VALID);
+ new_const_node->name(name + "_DS");
+
+ if (const_node->dtype() == loco::DataType::FLOAT32)
+ {
+ auto const_items = const_node->size<loco::DataType::FLOAT32>();
+ auto f_data = std::make_unique<float[]>(const_items);
+ for (size_t i = 0; i < const_items; ++i)
+ f_data[i] = const_node->at<loco::DataType::FLOAT32>(i);
+
+ sparsity::TfLiteSparsity sp = to_tflite_sparsity(const_node->sparsityparam());
+ sparsity::FormatConverter<float> converter(dense_shape, sp);
+ converter.SparseToDense(f_data.get());
+ const auto &data_dense = converter.GetData();
+ assert(data_dense.size() == dim_size);
+
+ for (uint32_t i = 0; i < dim_size; ++i)
+ new_const_node->at<loco::DataType::FLOAT32>(i) = data_dense[i];
+
+ luci::freeTfLiteSparsity(sp);
+ }
+ else
+ {
+ assert(const_node->dtype() == loco::DataType::FLOAT16);
+
+ auto const_items = const_node->size<loco::DataType::FLOAT16>();
+ auto f_data = std::make_unique<uint16_t[]>(const_items);
+ for (size_t i = 0; i < const_items; ++i)
+ f_data[i] = const_node->at<loco::DataType::FLOAT16>(i);
+
+ // Primitive type for FLOAT16 is UINT16
+ sparsity::TfLiteSparsity sp = to_tflite_sparsity(const_node->sparsityparam());
+ sparsity::FormatConverter<uint16_t> converter(dense_shape, sp);
+ converter.SparseToDense(f_data.get());
+ const auto &data_dense = converter.GetData();
+ assert(data_dense.size() == dim_size);
+ for (uint32_t i = 0; i < dim_size; ++i)
+ new_const_node->at<loco::DataType::FLOAT16>(i) = data_dense[i];
+
+ luci::freeTfLiteSparsity(sp);
+ }
+
+ return new_const_node;
+}
+
+/**
+ * @brief Fold Densify if input is Sparse Constant
+ */
+bool fold_densify(luci::CircleDensify *densify)
+{
+ auto const_input = dynamic_cast<luci::CircleConst *>(densify->input());
+ if (not const_input)
+ return false;
+
+ if (not is_foldable_const(const_input))
+ return false;
+
+ auto dense_const = densified_const_node(const_input);
+ assert(dense_const);
+
+ loco::replace(densify).with(dense_const);
+ luci::add_origin(dense_const, luci::composite_origin(
+ {luci::get_origin(densify), luci::get_origin(const_input)}));
+
+ return true;
+}
+
+} // namespace
+
+namespace luci
+{
+
+/**
+ * BEFORE
+ *
+ * [CircleConst](sparse)
+ * |
+ * [CircleDensify]
+ * |
+ * [CircleNode]
+ * |
+ *
+ * AFTER
+ *
+ * [CircleConst](dense) [CircleConst](sparse)
+ * | |
+ * [CircleNode] [CircleDensify]
+ * |
+ */
+bool FoldDensifyPass::run(loco::Graph *g)
+{
+ bool changed = false;
+
+ for (auto node : loco::active_nodes(loco::output_nodes(g)))
+ {
+ if (auto densify = dynamic_cast<luci::CircleDensify *>(node))
+ {
+ if (fold_densify(densify))
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+} // namespace luci