CMS 3D CMS Logo

nnet_activation.h
Go to the documentation of this file.
1 //
2 // rfnoc-hls-neuralnet: Vivado HLS code for neural-net building blocks
3 //
4 // Copyright (C) 2017 EJ Kreinar
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 #ifndef NNET_ACTIVATION_H_
21 #define NNET_ACTIVATION_H_
22 
23 #include <cmath>
24 #include "ap_fixed.h"
25 #include "nnet_common.h"
26 
27 namespace nnet {
28 
29  struct activ_config {
30  // IO size
31  static const unsigned n_in = 10;
32 
33  // Internal info
34  static const unsigned table_size = 1024;
35 
36  // Resource reuse info
37  static const unsigned io_type = io_parallel;
38  static const unsigned reuse_factor = 1;
39 
40  // Internal data type definitions
41  //typedef ap_fixed<18,8> table_t;
42  typedef float table_t;
43  };
44 
45  // *************************************************
46  // LINEAR Activation -- See Issue 53
47  // *************************************************
48  template <class data_T, class res_T, typename CONFIG_T>
49  void linear(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in]) {
50  for (unsigned ii = 0; ii < CONFIG_T::n_in; ii++) {
51  res[ii] = data[ii];
52  }
53  }
54 
55  // *************************************************
56  // RELU Activation
57  // *************************************************
58  template <class data_T, class res_T, typename CONFIG_T>
59  void relu(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in]) {
60  data_T datareg;
61  for (unsigned ii = 0; ii < CONFIG_T::n_in; ii++) {
62  datareg = data[ii];
63  if (datareg > 0)
64  res[ii] = datareg;
65  else
66  res[ii] = 0;
67  }
68  }
69 
70  template <class data_T, class res_T, int MAX_INT, typename CONFIG_T>
71  void relu_max(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in]) {
72  data_T datareg;
73  for (unsigned ii = 0; ii < CONFIG_T::n_in; ii++) {
74  datareg = data[ii];
75  if (datareg < 0)
76  res[ii] = 0;
77  else if (datareg > MAX_INT)
78  res[ii] = MAX_INT;
79  else
80  res[ii] = datareg;
81  }
82  }
83 
84  template <class data_T, class res_T, typename CONFIG_T>
85  void relu6(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in]) {
86  relu_max<data_T, res_T, 6, CONFIG_T>(data, res);
87  }
88 
89  // *************************************************
90  // Sigmoid Activation
91  // *************************************************
92  template <class out_T>
93  inline out_T sigmoid_fcn_float(float input) {
94  return 1.0 / (1 + exp(-input));
95  }
96 
97  template <class res_T, typename CONFIG_T, int N_TABLE>
98  void init_sigmoid_table(res_T table_out[N_TABLE]) {
99  // Default logistic sigmoid function:
100  // result = 1/(1+e^(-x))
101  for (unsigned ii = 0; ii < N_TABLE; ii++) {
102  // First, convert from table index to X-value (signed 8-bit, range -8 to +8)
103  float in_val = 2 * 8.0 * (ii - float(N_TABLE) / 2.0) / float(N_TABLE);
104  // Next, compute lookup table function
105  res_T real_val = sigmoid_fcn_float<res_T>(in_val);
106  //std::cout << "Lookup table In Value: " << in_val << " Result: " << real_val << std::endl;
107  table_out[ii] = (res_T)real_val;
108  }
109  }
110 
111  template <class data_T, class res_T, typename CONFIG_T>
112  void sigmoid(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in]) {
113  // Initialize the lookup table
114  res_T sigmoid_table[CONFIG_T::table_size];
115  init_sigmoid_table<res_T, CONFIG_T, CONFIG_T::table_size>(sigmoid_table);
116 
117  // Index into the lookup table based on data
118  int data_round;
119  unsigned index;
120  for (unsigned ii = 0; ii < CONFIG_T::n_in; ii++) {
121  data_round = data[ii] * CONFIG_T::table_size / 16;
122  index = data_round + 8 * CONFIG_T::table_size / 16;
123  /*if (index < 0)
124  index = 0;*/
125  if (index > CONFIG_T::table_size - 1)
126  index = CONFIG_T::table_size - 1;
127  res[ii] = (res_T)sigmoid_table[index];
128  }
129  }
130 
131  // *************************************************
132  // Softmax Activation
133  // *************************************************
134  inline float exp_fcn_float(float input) { return exp(input); }
135 
136  template <typename CONFIG_T, int N_TABLE>
137  void init_exp_table(typename CONFIG_T::table_t table_out[N_TABLE]) {
138  for (unsigned ii = 0; ii < N_TABLE; ii++) {
139  // First, convert from table index to X-value (signed 8-bit, range -8 to +8)
140  float in_val = 2 * 8.0 * (ii - float(N_TABLE) / 2.0) / float(N_TABLE);
141  // Next, compute lookup table function
142  typename CONFIG_T::table_t real_val = exp_fcn_float(in_val);
143  //std::cout << "Lookup table In Value: " << in_val << " Result: " << real_val << std::endl;
144  table_out[ii] = real_val;
145  }
146  }
147 
148  template <typename CONFIG_T, int N_TABLE>
149  void init_invert_table(typename CONFIG_T::table_t table_out[N_TABLE]) {
150  // Inversion function:
151  // result = 1/x
152  for (unsigned ii = 0; ii < N_TABLE; ii++) {
153  // First, convert from table index to X-value (signed 8-bit, range 0 to +64)
154  float in_val = 64.0 * ii / float(N_TABLE);
155  // Next, compute lookup table function
156  if (in_val > 0.0)
157  table_out[ii] = 1.0 / in_val;
158  else
159  table_out[ii] = 0.0;
160  }
161  }
162 
163  template <class data_T, class res_T, typename CONFIG_T>
164  void softmax(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in]) {
165  // Initialize the lookup table
166  typename CONFIG_T::table_t exp_table[CONFIG_T::table_size];
167  init_exp_table<CONFIG_T, CONFIG_T::table_size>(exp_table);
168 
169  typename CONFIG_T::table_t invert_table[CONFIG_T::table_size];
170  init_invert_table<CONFIG_T, CONFIG_T::table_size>(invert_table);
171 
172  // Index into the lookup table based on data for exponentials
173  typename CONFIG_T::table_t exp_res[CONFIG_T::n_in]; // different, independent, fixed point precision
174  typename CONFIG_T::table_t exp_diff_res[CONFIG_T::n_in]
175  [CONFIG_T::n_in]; // different, independent, fixed point precision
176  int data_round;
177  int index;
178  for (int ii = 0; ii < CONFIG_T::n_in; ii++) {
179  exp_res[ii] = 0;
180  }
181  for (int ii = 0; ii < CONFIG_T::n_in; ii++) {
182  for (int jj = 0; jj < CONFIG_T::n_in; jj++) {
183  if (ii == jj)
184  exp_diff_res[ii][jj] = 1;
185  else {
186  data_round = (data[jj] - data[ii]) * CONFIG_T::table_size / 16;
187  index = data_round + 8 * CONFIG_T::table_size / 16;
188  if (index < 0)
189  index = 0;
190  if (index > CONFIG_T::table_size - 1)
191  index = CONFIG_T::table_size - 1;
192  exp_diff_res[ii][jj] = exp_table[index];
193  }
194  exp_res[ii] += exp_diff_res[ii][jj];
195  }
196  }
197 
198  //Second loop to invert
199  for (unsigned ii = 0; ii < CONFIG_T::n_in; ii++) {
200  int exp_res_index = exp_res[ii] * CONFIG_T::table_size / 64;
201  if (exp_res_index < 0)
202  exp_res_index = 0;
203  if (exp_res_index > CONFIG_T::table_size - 1)
204  exp_res_index = CONFIG_T::table_size - 1;
205  //typename CONFIG_T::table_t exp_res_invert = invert_table[exp_res_index];
206  res[ii] = (res_T)invert_table[exp_res_index];
207  }
208  }
209 
210  // *************************************************
211  // TanH Activation
212  // *************************************************
213  template <typename CONFIG_T, int N_TABLE>
214  void init_tanh_table(typename CONFIG_T::table_t table_out[N_TABLE]) {
215  // Implement tanh lookup
216  for (unsigned ii = 0; ii < N_TABLE; ii++) {
217  // First, convert from table index to X-value (signed 8-bit, range -4 to +4)
218  float in_val = 2 * 4.0 * (ii - float(N_TABLE) / 2.0) / float(N_TABLE);
219  // Next, compute lookup table function
220  typename CONFIG_T::table_t real_val = tanh(in_val);
221  //std::cout << "Tanh: Lookup table Index: " << ii<< " In Value: " << in_val << " Result: " << real_val << std::endl;
222  table_out[ii] = real_val;
223  }
224  }
225 
226  template <class data_T, class res_T, typename CONFIG_T>
227  void tanh(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in]) {
228  // Initialize the lookup table
229  typename CONFIG_T::table_t tanh_table[CONFIG_T::table_size];
230  init_tanh_table<CONFIG_T, CONFIG_T::table_size>(tanh_table);
231 
232  // Index into the lookup table based on data
233  int data_round;
234  int index;
235  for (int ii = 0; ii < CONFIG_T::n_in; ii++) {
236  data_round = data[ii] * CONFIG_T::table_size / 8;
237  index = data_round + 4 * CONFIG_T::table_size / 8;
238  //std::cout << "Input: " << data[ii] << " Round: " << data_round << " Index: " << index << std::endl;
239  if (index < 0)
240  index = 0;
241  if (index > CONFIG_T::table_size - 1)
242  index = CONFIG_T::table_size - 1;
243  res[ii] = (res_T)tanh_table[index];
244  }
245  }
246 
247 } // namespace nnet
248 
249 #endif
void init_exp_table(typename CONFIG_T::table_t table_out[N_TABLE])
void tanh(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
Definition: Electron.h:6
static std::string const input
Definition: EdmProvDump.cc:50
out_T sigmoid_fcn_float(float input)
void init_invert_table(typename CONFIG_T::table_t table_out[N_TABLE])
ii
Definition: cuy.py:589
void linear(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
void softmax(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
static const unsigned reuse_factor
void init_tanh_table(typename CONFIG_T::table_t table_out[N_TABLE])
void relu6(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
static constexpr int N_TABLE
static const unsigned n_in
static const unsigned table_size
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:80
void relu_max(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
void init_sigmoid_table(res_T table_out[N_TABLE])
void sigmoid(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
void relu(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
float exp_fcn_float(float input)