|
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 | | -/* |
21 | | -* PLACEHOLDER - The common pass bn_quant.py includes both parallel and streaming BN; streaming is currently not supported in Quartus |
22 | | -*/ |
23 | | - |
24 | 1 | #ifndef NNET_BATCHNORM_STREAM_H_ |
25 | 2 | #define NNET_BATCHNORM_STREAM_H_ |
26 | 3 |
|
27 | 4 | #include "nnet_common.h" |
28 | 5 | #include "nnet_helpers.h" |
29 | 6 | #include "nnet_mult.h" |
| 7 | +#include "nnet_types.h" |
| 8 | + |
| 9 | +namespace nnet { |
| 10 | + |
| 11 | +// **************************************************** |
| 12 | +// Streaming Batch Normalization |
| 13 | +// **************************************************** |
| 14 | +template<class data_T, class res_T, typename CONFIG_T> |
| 15 | +void normalize( |
| 16 | + stream<data_T> &data, |
| 17 | + stream<res_T> &res, |
| 18 | + const typename CONFIG_T::scale_t scale[CONFIG_T::n_in], |
| 19 | + const typename CONFIG_T::bias_t bias[CONFIG_T::n_in] |
| 20 | +) { |
| 21 | + |
| 22 | + constexpr unsigned multiplier_limit = DIV_ROUNDUP(CONFIG_T::n_in, CONFIG_T::reuse_factor); |
| 23 | + constexpr unsigned pipeline = CONFIG_T::n_in / multiplier_limit; |
| 24 | + CONFIG_T::template product<typename data_T::value_type, typename CONFIG_T::scale_t>::limit(multiplier_limit); |
| 25 | + |
| 26 | + BatchNormLoop: |
| 27 | + #pragma ii pipeline |
| 28 | + for (int i = 0; i < CONFIG_T::n_in / data_T::size; i++) { |
| 29 | + data_T in_data = data.read(); |
| 30 | + res_T out_data; |
| 31 | + |
| 32 | + BatchNormpack: |
| 33 | + #pragma unroll |
| 34 | + for (int j = 0; j < data_T::size; j++) { |
| 35 | + int norm_index; |
| 36 | + if (CONFIG_T::n_filt==-1) norm_index = i * data_T::size + j; |
| 37 | + else norm_index = j % CONFIG_T::n_filt; |
| 38 | + out_data[j] = CONFIG_T::template product<typename data_T::value_type, typename CONFIG_T::scale_t>::product(in_data[j], scale[norm_index]) + bias[norm_index]; |
| 39 | + } |
| 40 | + |
| 41 | + res.write(out_data); |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +// **************************************************** |
| 46 | +// Merged Batch Normalization and Quantized Tanh |
| 47 | +// **************************************************** |
| 48 | +template<class data_T, typename CONFIG_T> |
| 49 | +void normalize_binary_tanh( |
| 50 | + stream<data_T> &data, |
| 51 | + stream<nnet::array<ac_int<1, false>, CONFIG_T::n_in>> &res, |
| 52 | + const typename data_T::value_type threshold[CONFIG_T::n_in] |
| 53 | +) { |
| 54 | + |
| 55 | + BinaryNormLoop: |
| 56 | + #pragma ii 1 |
| 57 | + for (int i = 0; i < CONFIG_T::n_in / data_T::size; i++) { |
| 58 | + data_T in_data = data.read(); |
| 59 | + nnet::array<ac_int<1, false>, CONFIG_T::n_in> out_data; |
| 60 | + |
| 61 | + BatchNormPack: |
| 62 | + #pragma unroll |
| 63 | + for (int j = 0; j < data_T::size; j++) { |
| 64 | + out_data[j] = (in_data[j] > threshold[i * data_T::size + j]) ? 1 : 0; |
| 65 | + } |
| 66 | + |
| 67 | + res.write(out_data); |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +template<class data_T, typename CONFIG_T> |
| 72 | +void normalize_ternary_tanh( |
| 73 | + stream<data_T> &data, |
| 74 | + stream<nnet::array<ac_int<2, true>, CONFIG_T::n_in>> &res, |
| 75 | + const typename data_T::value_type threshold_hi[CONFIG_T::n_in], |
| 76 | + const typename data_T::value_type threshold_lo[CONFIG_T::n_in] |
| 77 | +) { |
| 78 | + |
| 79 | + TernaryNormLoop: |
| 80 | + #pragma ii 1 |
| 81 | + for (int i = 0; i < CONFIG_T::n_in / data_T::size; i++) { |
| 82 | + data_T in_data = data.read(); |
| 83 | + nnet::array<ac_int<2, true>, CONFIG_T::n_in> out_data; |
| 84 | + |
| 85 | + BatchNormPack: |
| 86 | + #pragma unroll |
| 87 | + for (int j = 0; j < data_T::size; j++) { |
| 88 | + int norm_index = i * data_T::size + j; |
| 89 | + if (in_data[j] > threshold_hi[norm_index]) out_data[j] = 1; |
| 90 | + else if (in_data[j] <= threshold_lo[norm_index]) out_data[j] = -1; |
| 91 | + else out_data[j] = 0; |
| 92 | + } |
| 93 | + |
| 94 | + res.write(out_data); |
| 95 | + } |
| 96 | +} |
30 | 97 |
|
31 | | -namespace nnet {} |
| 98 | +} |
32 | 99 |
|
33 | 100 | #endif |
0 commit comments