2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "souschef/Data/Gaussian.h"
18 #include "souschef/LexicalCast.h"
25 #include <limits> // std::numeric_limits
33 static std::vector<uint8_t> generate_gaussian(int32_t count, float mean, float stddev,
34 std::minstd_rand::result_type seed)
36 std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)};
37 std::normal_distribution<float> dist{mean, stddev};
39 std::vector<uint8_t> res;
41 constexpr float max_cap = std::numeric_limits<T>::max();
42 constexpr float min_cap = std::numeric_limits<T>::lowest();
43 for (uint32_t n = 0; n < count; ++n)
45 float raw_value = dist(rand);
46 const float capped_value = std::max(min_cap, std::min(max_cap, raw_value));
47 auto const value = static_cast<T>(capped_value);
48 auto const arr = reinterpret_cast<const uint8_t *>(&value);
50 for (uint32_t b = 0; b < sizeof(T); ++b)
52 res.emplace_back(arr[b]);
60 static std::vector<uint8_t> generate_gaussian(int32_t count, float mean, float stddev)
62 auto time_stamp = std::chrono::system_clock::now().time_since_epoch().count();
64 // Note this is implementation defined, change if needed.
65 auto seed = static_cast<std::minstd_rand::result_type>(time_stamp);
67 return generate_gaussian<T>(count, mean, stddev, seed);
70 std::vector<uint8_t> GaussianFloat32DataChef::generate(int32_t count) const
72 return generate_gaussian<float>(count, _mean, _stddev);
75 std::vector<uint8_t> GaussianFloat16DataChef::generate(int32_t count) const
77 auto time_stamp = std::chrono::system_clock::now().time_since_epoch().count();
78 auto seed = static_cast<std::minstd_rand::result_type>(time_stamp);
80 std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)};
81 std::normal_distribution<float> dist{_mean, _stddev};
83 std::vector<uint8_t> res;
85 constexpr float max_cap = 1e9;
86 constexpr float min_cap = -1e9;
87 for (uint32_t n = 0; n < count; ++n)
89 float raw_value = dist(rand);
90 const float capped_value = std::max(min_cap, std::min(max_cap, raw_value));
91 const uint16_t value = fp16_ieee_from_fp32_value(capped_value);
92 auto const arr = reinterpret_cast<const uint8_t *>(&value);
94 for (uint32_t b = 0; b < sizeof(uint16_t); ++b)
96 res.emplace_back(arr[b]);
103 std::vector<uint8_t> GaussianInt32DataChef::generate(int32_t count) const
105 return generate_gaussian<int32_t>(count, _mean, _stddev);
108 std::vector<uint8_t> GaussianInt16DataChef::generate(int32_t count) const
110 return generate_gaussian<int16_t>(count, _mean, _stddev);
113 std::vector<uint8_t> GaussianUint8DataChef::generate(int32_t count) const
115 return generate_gaussian<uint8_t>(count, _mean, _stddev);
118 std::unique_ptr<DataChef> GaussianFloat32DataChefFactory::create(const Arguments &args) const
120 if (args.count() != 2)
122 throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
125 auto const mean = to_number<float>(args.value(0));
126 auto const stddev = to_number<float>(args.value(1));
128 return std::unique_ptr<DataChef>{new GaussianFloat32DataChef{mean, stddev}};
131 std::unique_ptr<DataChef> GaussianInt32DataChefFactory::create(const Arguments &args) const
133 if (args.count() != 2)
135 throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
138 auto const mean = to_number<float>(args.value(0));
139 auto const stddev = to_number<float>(args.value(1));
141 return std::unique_ptr<DataChef>{new GaussianInt32DataChef{mean, stddev}};
144 std::unique_ptr<DataChef> GaussianInt16DataChefFactory::create(const Arguments &args) const
146 if (args.count() != 2)
148 throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
151 auto const mean = to_number<float>(args.value(0));
152 auto const stddev = to_number<float>(args.value(1));
154 return std::unique_ptr<DataChef>{new GaussianInt16DataChef{mean, stddev}};
157 std::unique_ptr<DataChef> GaussianUint8DataChefFactory::create(const Arguments &args) const
159 if (args.count() != 2)
161 throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
164 auto const mean = to_number<float>(args.value(0));
165 auto const stddev = to_number<float>(args.value(1));
167 return std::unique_ptr<DataChef>{new GaussianUint8DataChef{mean, stddev}};
170 std::unique_ptr<DataChef> GaussianFloat16DataChefFactory::create(const Arguments &args) const
172 if (args.count() != 2)
174 throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
177 auto const mean = to_number<float>(args.value(0));
178 auto const stddev = to_number<float>(args.value(1));
180 return std::unique_ptr<DataChef>{new GaussianFloat16DataChef{mean, stddev}};
183 } // namespace souschef