diff options
Diffstat (limited to 'compiler/souschef/src/Gaussian.cpp')
-rw-r--r-- | compiler/souschef/src/Gaussian.cpp | 121 |
1 files changed, 91 insertions, 30 deletions
diff --git a/compiler/souschef/src/Gaussian.cpp b/compiler/souschef/src/Gaussian.cpp index 4a5083d8e..71ab56792 100644 --- a/compiler/souschef/src/Gaussian.cpp +++ b/compiler/souschef/src/Gaussian.cpp @@ -22,26 +22,32 @@ #include <cassert> #include <stdexcept> +#include <limits> // std::numeric_limits + +#include <fp16.h> namespace souschef { -std::vector<uint8_t> GaussianFloat32DataChef::generate(int32_t count) const +template <typename T> +static std::vector<uint8_t> generate_gaussian(int32_t count, float mean, float stddev, + std::minstd_rand::result_type seed) { - // TODO Support seed value override - auto seed = std::chrono::system_clock::now().time_since_epoch().count(); - std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)}; - std::normal_distribution<float> dist{_mean, _stddev}; + std::normal_distribution<float> dist{mean, stddev}; std::vector<uint8_t> res; + constexpr float max_cap = std::numeric_limits<T>::max(); + constexpr float min_cap = std::numeric_limits<T>::lowest(); for (uint32_t n = 0; n < count; ++n) { - auto const value = dist(rand); + float raw_value = dist(rand); + const float capped_value = std::max(min_cap, std::min(max_cap, raw_value)); + auto const value = static_cast<T>(capped_value); auto const arr = reinterpret_cast<const uint8_t *>(&value); - for (uint32_t b = 0; b < sizeof(float); ++b) + for (uint32_t b = 0; b < sizeof(T); ++b) { res.emplace_back(arr[b]); } @@ -50,22 +56,42 @@ std::vector<uint8_t> GaussianFloat32DataChef::generate(int32_t count) const return res; } -std::vector<uint8_t> GaussianInt32DataChef::generate(int32_t count) const +template <typename T> +static std::vector<uint8_t> generate_gaussian(int32_t count, float mean, float stddev) { - // TODO Support seed value override - auto seed = std::chrono::system_clock::now().time_since_epoch().count(); + auto time_stamp = std::chrono::system_clock::now().time_since_epoch().count(); + + // Note this is implementation defined, change if needed. + auto seed = static_cast<std::minstd_rand::result_type>(time_stamp); + + return generate_gaussian<T>(count, mean, stddev, seed); +} + +std::vector<uint8_t> GaussianFloat32DataChef::generate(int32_t count) const +{ + return generate_gaussian<float>(count, _mean, _stddev); +} + +std::vector<uint8_t> GaussianFloat16DataChef::generate(int32_t count) const +{ + auto time_stamp = std::chrono::system_clock::now().time_since_epoch().count(); + auto seed = static_cast<std::minstd_rand::result_type>(time_stamp); std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)}; std::normal_distribution<float> dist{_mean, _stddev}; std::vector<uint8_t> res; + constexpr float max_cap = 1e9; + constexpr float min_cap = -1e9; for (uint32_t n = 0; n < count; ++n) { - auto const value = static_cast<int32_t>(dist(rand)); + float raw_value = dist(rand); + const float capped_value = std::max(min_cap, std::min(max_cap, raw_value)); + const uint16_t value = fp16_ieee_from_fp32_value(capped_value); auto const arr = reinterpret_cast<const uint8_t *>(&value); - for (uint32_t b = 0; b < sizeof(int32_t); ++b) + for (uint32_t b = 0; b < sizeof(uint16_t); ++b) { res.emplace_back(arr[b]); } @@ -74,28 +100,24 @@ std::vector<uint8_t> GaussianInt32DataChef::generate(int32_t count) const return res; } -std::vector<uint8_t> GaussianUint8DataChef::generate(int32_t count) const +std::vector<uint8_t> GaussianInt32DataChef::generate(int32_t count) const { - // TODO Support seed value override - auto seed = std::chrono::system_clock::now().time_since_epoch().count(); - - std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)}; - std::normal_distribution<float> dist{_mean, _stddev}; - - std::vector<uint8_t> res; + return generate_gaussian<int32_t>(count, _mean, _stddev); +} - for (uint32_t n = 0; n < count; ++n) - { - auto const value = static_cast<uint8_t>(dist(rand)); // uint8_t for data type - auto const arr = reinterpret_cast<const uint8_t *>(&value); // uint8_t for byte streaming +std::vector<uint8_t> GaussianInt16DataChef::generate(int32_t count) const +{ + return generate_gaussian<int16_t>(count, _mean, _stddev); +} - for (uint32_t b = 0; b < sizeof(uint8_t); ++b) - { - res.emplace_back(arr[b]); - } - } +std::vector<uint8_t> GaussianUint8DataChef::generate(int32_t count) const +{ + return generate_gaussian<uint8_t>(count, _mean, _stddev); +} - return res; +std::vector<uint8_t> GaussianInt8DataChef::generate(int32_t count) const +{ + return generate_gaussian<int8_t>(count, _mean, _stddev); } std::unique_ptr<DataChef> GaussianFloat32DataChefFactory::create(const Arguments &args) const @@ -124,6 +146,19 @@ std::unique_ptr<DataChef> GaussianInt32DataChefFactory::create(const Arguments & return std::unique_ptr<DataChef>{new GaussianInt32DataChef{mean, stddev}}; } +std::unique_ptr<DataChef> GaussianInt16DataChefFactory::create(const Arguments &args) const +{ + if (args.count() != 2) + { + throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"}; + } + + auto const mean = to_number<float>(args.value(0)); + auto const stddev = to_number<float>(args.value(1)); + + return std::unique_ptr<DataChef>{new GaussianInt16DataChef{mean, stddev}}; +} + std::unique_ptr<DataChef> GaussianUint8DataChefFactory::create(const Arguments &args) const { if (args.count() != 2) @@ -137,4 +172,30 @@ std::unique_ptr<DataChef> GaussianUint8DataChefFactory::create(const Arguments & return std::unique_ptr<DataChef>{new GaussianUint8DataChef{mean, stddev}}; } +std::unique_ptr<DataChef> GaussianInt8DataChefFactory::create(const Arguments &args) const +{ + if (args.count() != 2) + { + throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"}; + } + + auto const mean = to_number<float>(args.value(0)); + auto const stddev = to_number<float>(args.value(1)); + + return std::unique_ptr<DataChef>{new GaussianInt8DataChef{mean, stddev}}; +} + +std::unique_ptr<DataChef> GaussianFloat16DataChefFactory::create(const Arguments &args) const +{ + if (args.count() != 2) + { + throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"}; + } + + auto const mean = to_number<float>(args.value(0)); + auto const stddev = to_number<float>(args.value(1)); + + return std::unique_ptr<DataChef>{new GaussianFloat16DataChef{mean, stddev}}; +} + } // namespace souschef |