summaryrefslogtreecommitdiff
path: root/compiler/record-minmax/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/record-minmax/src')
-rw-r--r--compiler/record-minmax/src/HDF5Importer.cpp28
-rw-r--r--compiler/record-minmax/src/MinMaxObserver.cpp32
-rw-r--r--compiler/record-minmax/src/RecordMinMax.cpp129
3 files changed, 164 insertions, 25 deletions
diff --git a/compiler/record-minmax/src/HDF5Importer.cpp b/compiler/record-minmax/src/HDF5Importer.cpp
index a0e65eeb7..cfb270ce0 100644
--- a/compiler/record-minmax/src/HDF5Importer.cpp
+++ b/compiler/record-minmax/src/HDF5Importer.cpp
@@ -59,7 +59,30 @@ DataType toInternalDtype(const H5::DataType &h5_type)
{
return DataType::S64;
}
- // Only support three datatypes for now
+ if (h5_type.getClass() == H5T_class_t::H5T_ENUM)
+ {
+ // We follow the numpy format
+ // In numpy 1.19.0, np.bool_ is saved as H5T_ENUM
+ // - (name, value) -> (FALSE, 0) and (TRUE, 1)
+ // - value dtype is H5T_STD_I8LE
+ // TODO Find a general way to recognize BOOL type
+ char name[10];
+ int8_t value[2] = {0, 1};
+ if (H5Tenum_nameof(h5_type.getId(), value, name, 10) < 0)
+ return DataType::Unknown;
+
+ if (std::string(name) != "FALSE")
+ return DataType::Unknown;
+
+ if (H5Tenum_nameof(h5_type.getId(), value + 1, name, 10) < 0)
+ return DataType::Unknown;
+
+ if (std::string(name) != "TRUE")
+ return DataType::Unknown;
+
+ return DataType::BOOL;
+ }
+ // TODO Support more datatypes
return DataType::Unknown;
}
@@ -125,6 +148,9 @@ void HDF5Importer::readTensor(int32_t record_idx, int32_t input_idx, DataType *d
case DataType::S64:
readTensorData(tensor, static_cast<int64_t *>(buffer));
break;
+ case DataType::BOOL:
+ readTensorData(tensor, static_cast<uint8_t *>(buffer));
+ break;
default:
throw std::runtime_error{"Unsupported data type for input data (.h5)"};
}
diff --git a/compiler/record-minmax/src/MinMaxObserver.cpp b/compiler/record-minmax/src/MinMaxObserver.cpp
index c22cb4132..40c9b730d 100644
--- a/compiler/record-minmax/src/MinMaxObserver.cpp
+++ b/compiler/record-minmax/src/MinMaxObserver.cpp
@@ -18,6 +18,8 @@
#include <luci/IR/CircleOpcode.h>
+#include <math.h>
+
using DataType = luci_interpreter::DataType;
namespace record_minmax
@@ -51,6 +53,12 @@ void MinMaxObserver::postTensorWrite(const luci::CircleNode *node,
return;
}
+ if (node->dtype() == DataType::BOOL)
+ {
+ // Bool type tensor is not quantized
+ return;
+ }
+
// Only support recording of float32 values
if (tensor->element_type() != DataType::FLOAT32)
throw std::runtime_error("Tensor's data type is not float");
@@ -59,9 +67,27 @@ void MinMaxObserver::postTensorWrite(const luci::CircleNode *node,
const auto num_elements = tensor->shape().num_elements();
std::vector<float> buf(data, data + num_elements);
- auto minmax = std::minmax_element(buf.begin(), buf.end());
- float min = *minmax.first;
- float max = *minmax.second;
+
+ float max = std::numeric_limits<float>::lowest();
+ float min = std::numeric_limits<float>::max();
+
+ bool all_nan = true;
+ for (auto number : buf)
+ {
+ if (isnan(number))
+ continue;
+
+ all_nan = false;
+
+ if (number > max)
+ max = number;
+
+ if (number < min)
+ min = number;
+ }
+
+ if (all_nan)
+ throw std::runtime_error("All values are NaN(Not a Number)");
_minmax_data.recordMinMax(node, min, max);
}
diff --git a/compiler/record-minmax/src/RecordMinMax.cpp b/compiler/record-minmax/src/RecordMinMax.cpp
index cd5f29352..333ff5e3b 100644
--- a/compiler/record-minmax/src/RecordMinMax.cpp
+++ b/compiler/record-minmax/src/RecordMinMax.cpp
@@ -30,6 +30,7 @@
#include <numeric>
#include <stdexcept>
#include <iostream>
+#include <random>
using Shape = luci_interpreter::Shape;
using DataType = luci_interpreter::DataType;
@@ -37,6 +38,18 @@ using DataType = luci_interpreter::DataType;
namespace
{
+std::vector<uint8_t> genRandomBoolData(std::mt19937 &gen, uint32_t num_elements)
+{
+ std::uniform_int_distribution<> dist(0, 1);
+ std::vector<uint8_t> input_data(num_elements);
+
+ // Write random data
+ for (auto &iter : input_data)
+ iter = static_cast<uint8_t>(dist(gen));
+
+ return input_data;
+}
+
/**
* @brief getTensorSize will return size in bytes
*/
@@ -68,6 +81,38 @@ void verifyTypeShape(const luci::CircleInput *input_node, const DataType &dtype,
}
}
+void update_quantparam(record_minmax::MinMaxObserver *observer, const std::string &mode,
+ float min_percentile, float max_percentile)
+{
+ auto minmax_map = observer->minMaxData()->getMap();
+ for (auto iter = minmax_map->begin(); iter != minmax_map->end(); ++iter)
+ {
+ auto node = iter->first;
+ auto minmax = iter->second;
+
+ float min{0.0f}, max{0.0f};
+ if (mode == "percentile")
+ {
+ min = record_minmax::getNthPercentile(minmax.min_vector, min_percentile);
+ max = record_minmax::getNthPercentile(minmax.max_vector, max_percentile);
+ }
+ else if (mode == "moving_average")
+ {
+ min = record_minmax::getMovingAverage(minmax.min_vector, 0.9, 16, true);
+ max = record_minmax::getMovingAverage(minmax.max_vector, 0.9, 16, false);
+ }
+ assert(mode == "percentile" || mode == "moving_average");
+ auto quantparam = std::make_unique<luci::CircleQuantParam>();
+ quantparam->min.push_back(min);
+ quantparam->max.push_back(max);
+
+ assert(node->quantparam() == nullptr);
+
+ auto mutable_node = const_cast<luci::CircleNode *>(node);
+ mutable_node->quantparam(std::move(quantparam));
+ }
+}
+
} // namespace
namespace record_minmax
@@ -169,33 +214,75 @@ void RecordMinMax::profileData(const std::string &mode, const std::string &input
throw std::runtime_error("HDF5 error occurred.");
}
- auto minmax_map = _observer->minMaxData()->getMap();
- for (auto iter = minmax_map->begin(); iter != minmax_map->end(); ++iter)
+ update_quantparam(_observer.get(), mode, min_percentile, max_percentile);
+}
+
+void RecordMinMax::profileDataWithRandomInputs(const std::string &mode, float min_percentile,
+ float max_percentile)
+{
+ // We use three randomly-generated records
+ const uint32_t num_records = 3;
+
+ const auto input_nodes = loco::input_nodes(_module->graph());
+ const auto num_inputs = input_nodes.size();
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_real_distribution<> dist(-5, 5);
+
+ for (int32_t record_idx = 0; record_idx < num_records; record_idx++)
{
- auto node = iter->first;
- auto minmax = iter->second;
+ std::cout << "Recording " << record_idx << "'th data" << std::endl;
- float min{0.0f}, max{0.0f};
- if (mode == "percentile")
+ for (int32_t input_idx = 0; input_idx < num_inputs; input_idx++)
{
- min = getNthPercentile(minmax.min_vector, min_percentile);
- max = getNthPercentile(minmax.max_vector, max_percentile);
- }
- else if (mode == "moving_average")
- {
- min = getMovingAverage(minmax.min_vector, 0.9, 16, true);
- max = getMovingAverage(minmax.max_vector, 0.9, 16, false);
- }
- assert(mode == "percentile" || mode == "moving_average");
- auto quantparam = std::make_unique<luci::CircleQuantParam>();
- quantparam->min.push_back(min);
- quantparam->max.push_back(max);
+ const auto *input_node = loco::must_cast<const luci::CircleInput *>(input_nodes[input_idx]);
+ assert(input_node->index() == input_idx);
+ uint32_t num_elements = 1;
+ for (uint32_t i = 0; i < input_node->rank(); i++)
+ {
+ if (!input_node->dim(i).known())
+ throw std::runtime_error("Input dimension must be known");
- assert(node->quantparam() == nullptr);
+ num_elements *= input_node->dim(i).value();
+ }
- auto mutable_node = const_cast<luci::CircleNode *>(node);
- mutable_node->quantparam(std::move(quantparam));
+ if (num_elements == 0)
+ throw std::runtime_error("Only support non-zero sized inputs");
+
+ // TODO Support more input data types
+ assert(input_node->dtype() == loco::DataType::FLOAT32 ||
+ input_node->dtype() == loco::DataType::BOOL);
+
+ if (input_node->dtype() == DataType::FLOAT32)
+ // clang-format off
+ {
+ std::vector<float> input_data(num_elements);
+
+ // Write random data
+ for (auto &iter : input_data)
+ iter = static_cast<float>(dist(gen));
+
+ // TODO: Input data is copied twice (file -> buffer (input_data) -> interpreter inputs)
+ // We can redcue the copy by directly writing data from file to interpreter inputs
+ _interpreter->writeInputTensor(input_node, input_data.data(),
+ input_data.size() * sizeof(float));
+ }
+ // clang-format on
+ else if (input_node->dtype() == DataType::BOOL)
+ {
+ auto input_data = genRandomBoolData(gen, num_elements);
+ _interpreter->writeInputTensor(input_node, input_data.data(),
+ input_data.size() * sizeof(uint8_t));
+ }
+ }
+
+ _interpreter->interpret();
}
+
+ std::cout << "Recording finished. Number of recorded data: " << num_records << std::endl;
+
+ update_quantparam(_observer.get(), mode, min_percentile, max_percentile);
}
void RecordMinMax::saveModel(const std::string &output_model_path)