Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / compiler / souschef / src / Gaussian.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
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
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "souschef/Data/Gaussian.h"
18 #include "souschef/LexicalCast.h"
19
20 #include <random>
21 #include <chrono>
22
23 #include <cassert>
24 #include <stdexcept>
25 #include <limits> // std::numeric_limits
26
27 #include <fp16.h>
28
29 namespace souschef
30 {
31
32 template <typename T>
33 static std::vector<uint8_t> generate_gaussian(int32_t count, float mean, float stddev,
34                                               std::minstd_rand::result_type seed)
35 {
36   std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)};
37   std::normal_distribution<float> dist{mean, stddev};
38
39   std::vector<uint8_t> res;
40
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)
44   {
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);
49
50     for (uint32_t b = 0; b < sizeof(T); ++b)
51     {
52       res.emplace_back(arr[b]);
53     }
54   }
55
56   return res;
57 }
58
59 template <typename T>
60 static std::vector<uint8_t> generate_gaussian(int32_t count, float mean, float stddev)
61 {
62   auto time_stamp = std::chrono::system_clock::now().time_since_epoch().count();
63
64   // Note this is implementation defined, change if needed.
65   auto seed = static_cast<std::minstd_rand::result_type>(time_stamp);
66
67   return generate_gaussian<T>(count, mean, stddev, seed);
68 }
69
70 std::vector<uint8_t> GaussianFloat32DataChef::generate(int32_t count) const
71 {
72   return generate_gaussian<float>(count, _mean, _stddev);
73 }
74
75 std::vector<uint8_t> GaussianFloat16DataChef::generate(int32_t count) const
76 {
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);
79
80   std::minstd_rand rand{static_cast<std::minstd_rand::result_type>(seed)};
81   std::normal_distribution<float> dist{_mean, _stddev};
82
83   std::vector<uint8_t> res;
84
85   constexpr float max_cap = 1e9;
86   constexpr float min_cap = -1e9;
87   for (uint32_t n = 0; n < count; ++n)
88   {
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);
93
94     for (uint32_t b = 0; b < sizeof(uint16_t); ++b)
95     {
96       res.emplace_back(arr[b]);
97     }
98   }
99
100   return res;
101 }
102
103 std::vector<uint8_t> GaussianInt32DataChef::generate(int32_t count) const
104 {
105   return generate_gaussian<int32_t>(count, _mean, _stddev);
106 }
107
108 std::vector<uint8_t> GaussianInt16DataChef::generate(int32_t count) const
109 {
110   return generate_gaussian<int16_t>(count, _mean, _stddev);
111 }
112
113 std::vector<uint8_t> GaussianUint8DataChef::generate(int32_t count) const
114 {
115   return generate_gaussian<uint8_t>(count, _mean, _stddev);
116 }
117
118 std::vector<uint8_t> GaussianInt8DataChef::generate(int32_t count) const
119 {
120   return generate_gaussian<int8_t>(count, _mean, _stddev);
121 }
122
123 std::unique_ptr<DataChef> GaussianFloat32DataChefFactory::create(const Arguments &args) const
124 {
125   if (args.count() != 2)
126   {
127     throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
128   }
129
130   auto const mean = to_number<float>(args.value(0));
131   auto const stddev = to_number<float>(args.value(1));
132
133   return std::unique_ptr<DataChef>{new GaussianFloat32DataChef{mean, stddev}};
134 }
135
136 std::unique_ptr<DataChef> GaussianInt32DataChefFactory::create(const Arguments &args) const
137 {
138   if (args.count() != 2)
139   {
140     throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
141   }
142
143   auto const mean = to_number<float>(args.value(0));
144   auto const stddev = to_number<float>(args.value(1));
145
146   return std::unique_ptr<DataChef>{new GaussianInt32DataChef{mean, stddev}};
147 }
148
149 std::unique_ptr<DataChef> GaussianInt16DataChefFactory::create(const Arguments &args) const
150 {
151   if (args.count() != 2)
152   {
153     throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
154   }
155
156   auto const mean = to_number<float>(args.value(0));
157   auto const stddev = to_number<float>(args.value(1));
158
159   return std::unique_ptr<DataChef>{new GaussianInt16DataChef{mean, stddev}};
160 }
161
162 std::unique_ptr<DataChef> GaussianUint8DataChefFactory::create(const Arguments &args) const
163 {
164   if (args.count() != 2)
165   {
166     throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
167   }
168
169   auto const mean = to_number<float>(args.value(0));
170   auto const stddev = to_number<float>(args.value(1));
171
172   return std::unique_ptr<DataChef>{new GaussianUint8DataChef{mean, stddev}};
173 }
174
175 std::unique_ptr<DataChef> GaussianInt8DataChefFactory::create(const Arguments &args) const
176 {
177   if (args.count() != 2)
178   {
179     throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
180   }
181
182   auto const mean = to_number<float>(args.value(0));
183   auto const stddev = to_number<float>(args.value(1));
184
185   return std::unique_ptr<DataChef>{new GaussianInt8DataChef{mean, stddev}};
186 }
187
188 std::unique_ptr<DataChef> GaussianFloat16DataChefFactory::create(const Arguments &args) const
189 {
190   if (args.count() != 2)
191   {
192     throw std::runtime_error{"invalid argument count: two arguments (mean/stddev) are expected"};
193   }
194
195   auto const mean = to_number<float>(args.value(0));
196   auto const stddev = to_number<float>(args.value(1));
197
198   return std::unique_ptr<DataChef>{new GaussianFloat16DataChef{mean, stddev}};
199 }
200
201 } // namespace souschef