CMS 3D CMS Logo

LutNeuronLayerFixedPoint.h
Go to the documentation of this file.
1 //============================================================================
2 // Name : LutNeuronLayerFixedPoint.h
3 // Author : Karol Bunkowski
4 // Created on: Mar 12, 2021
5 // Version :
6 // Copyright : All right reserved
7 // Description : Fixed point LUT layer
8 //============================================================================
9 
10 #ifndef L1Trigger_L1TMuonOverlapPhase2_LutNeuronlayerFixedPoint_h
11 #define L1Trigger_L1TMuonOverlapPhase2_LutNeuronlayerFixedPoint_h
12 
13 #include <ap_fixed.h>
14 #include <ap_int.h>
15 #include <array>
16 #include <limits>
17 #include <iomanip>
18 #include <cassert>
19 
20 #include <boost/property_tree/ptree.hpp>
21 
25 
26 namespace lutNN {
27  // constexpr for ceil(log2) from stackoverflow
28  constexpr size_t floorlog2(size_t i) {
29  if (!(i > 0))
30  throw cms::Exception("Incorrect input")
31  << "Argument of floorlog2 must be grater than 0, while " << i << " used.\n";
32  return i == 1 ? 0 : 1 + floorlog2(i >> 1);
33  }
34  constexpr size_t ceillog2(size_t i) {
35  if (!(i > 0))
36  throw cms::Exception("Incorrect input")
37  << "Argument of ceillog2 must be grater than 0, while " << i << " used.\n";
38  return i == 1 ? 0 : floorlog2(i - 1) + 1;
39  }
40 
41  template <int input_I, int input_F, size_t inputSize, int lut_I, int lut_F, int neurons, int output_I>
43  public:
44  static constexpr int input_W = input_I + input_F;
45  static constexpr int lut_W = lut_I + lut_F;
46 
47  //the lut out values sum
48  //static const int lutOutSum_I = lut_I + ceil(log2(inputSize)); //MB: ceil(log2(inputSize)) is not constexpr which makes issue for code-checks
49  static constexpr int lutOutSum_I = lut_I + ceillog2(inputSize);
50  static constexpr int lutOutSum_W = lutOutSum_I + lut_F;
51 
52  static constexpr int output_W = output_I + lut_F;
53 
54  //static_assert( (1<<input_I) <= lutSize);
55  static constexpr size_t lutSize = 1 << input_I;
56 
57  typedef std::array<ap_ufixed<input_W, input_I, AP_TRN, AP_SAT>, inputSize> inputArrayType;
58 
59  typedef std::array<ap_fixed<lutOutSum_W, lutOutSum_I>, neurons> lutSumArrayType;
60 
61  LutNeuronLayerFixedPoint() { //FIXME initialise name(name)
62  //static_assert(lut_I <= (output_I - ceil(log2(inputSize)) ), "not correct lut_I, output_I and inputSize"); //TODO
63 
64  LogTrace("l1tOmtfEventPrint") << "Constructing LutNeuronLayerFixedPoint " << name << "\n input_I "
65  << std::setw(2) << input_I << " input_F " << std::setw(2) << input_F
66  << " input_W " << std::setw(2) << input_W << " inputSize " << std::setw(2)
67  << inputSize << "\n lut_I " << std::setw(2) << lut_I << " lut_F "
68  << std::setw(2) << lut_F << " lut_W " << std::setw(2) << lut_W << " lutSize "
69  << std::setw(2) << lutSize << "\n lutOutSum_I " << std::setw(2) << lutOutSum_I
70  << " lutOutSum_W " << std::setw(2) << lutOutSum_W << "\n output_I "
71  << std::setw(2) << output_I << " output_W " << std::setw(2) << output_W
72  << "\n neurons " << std::setw(2) << neurons << "\n outOffset " << outOffset << " = "
73  << std::hex << outOffset << " width " << outOffset.width << std::dec;
74  }
75 
77 
78  void setName(std::string name) { this->name = name; }
79 
80  auto& getLutArray() { return lutArray; }
81 
83  const std::array<std::array<std::array<ap_fixed<output_W, output_I>, lutSize>, neurons>, inputSize>& lutArray) {
84  this->lutArray = lutArray;
85  }
86 
87  void save(boost::property_tree::ptree& tree, std::string keyPath) {
88  PUT_VAR(tree, keyPath + "." + name, input_I)
89  PUT_VAR(tree, keyPath + "." + name, input_F)
90  PUT_VAR(tree, keyPath + "." + name, inputSize)
91  PUT_VAR(tree, keyPath + "." + name, lut_I)
92  PUT_VAR(tree, keyPath + "." + name, lut_F)
93  PUT_VAR(tree, keyPath + "." + name, neurons)
94  PUT_VAR(tree, keyPath + "." + name, output_I)
95 
96  for (unsigned int iInput = 0; iInput < lutArray.size(); iInput++) {
97  for (unsigned int iNeuron = 0; iNeuron < lutArray[iInput].size(); iNeuron++) {
98  auto& lut = lutArray.at(iInput).at(iNeuron);
99  std::ostringstream ostr;
100  for (auto& a : lut) {
101  ostr << std::fixed << std::setprecision(19) << a.to_float() << ", ";
102  }
103  tree.put(keyPath + "." + name + ".lutArray." + std::to_string(iInput) + "." + std::to_string(iNeuron),
104  ostr.str());
105  }
106  }
107  }
108 
109  void load(boost::property_tree::ptree& tree, std::string keyPath) {
110  CHECK_VAR(tree, keyPath + "." + name, input_I)
111  CHECK_VAR(tree, keyPath + "." + name, input_F)
112  CHECK_VAR(tree, keyPath + "." + name, inputSize)
113  CHECK_VAR(tree, keyPath + "." + name, lut_I)
114  CHECK_VAR(tree, keyPath + "." + name, lut_F)
115  CHECK_VAR(tree, keyPath + "." + name, neurons)
116  CHECK_VAR(tree, keyPath + "." + name, output_I)
117 
118  for (unsigned int iInput = 0; iInput < lutArray.size(); iInput++) {
119  for (unsigned int iNeuron = 0; iNeuron < lutArray[iInput].size(); iNeuron++) {
120  auto& lut = lutArray.at(iInput).at(iNeuron);
121  auto str = tree.get<std::string>(keyPath + "." + name + ".lutArray." + std::to_string(iInput) + "." +
122  std::to_string(iNeuron));
123 
124  std::stringstream ss(str);
126 
127  for (auto& a : lut) {
128  if (std::getline(ss, item, ',')) {
129  a = std::stof(item, nullptr);
130  } else {
131  throw std::runtime_error(
132  "LutNeuronLayerFixedPoint::read: number of items get from file is smaller than lut size");
133  }
134  }
135  }
136  }
137  }
138 
140  for (unsigned int iNeuron = 0; iNeuron < lutOutSumArray.size(); iNeuron++) {
141  auto& lutOutSum = lutOutSumArray.at(iNeuron);
142  lutOutSum = 0;
143  for (unsigned int iInput = 0; iInput < inputArray.size(); iInput++) {
144  auto address = inputArray.at(iInput).to_uint(); //address in principle is unsigned
145  auto& lut = lutArray.at(iInput).at(iNeuron);
146 
147  auto addresPlus1 = address + 1;
148  if (addresPlus1 >= lut.size())
149  addresPlus1 = address;
150 
151  auto derivative = lut.at(addresPlus1) - lut.at(address); // must be signed
152 
153  //N.B. the address and fractionalPart is the same for all neurons, what matters for the firmware
154  ap_ufixed<input_W - input_I, 0> fractionalPart = inputArray.at(iInput);
155 
156  auto result = lut.at(address) + fractionalPart * derivative;
157  lutOutSum += result;
158  }
159 
160  lutOutSumArray.at(iNeuron) = lutOutSum;
161  }
162 
163  return lutOutSumArray;
164  }
165 
166  //Output without offset
167  auto& getLutOutSum() { return lutOutSumArray; }
168 
169  //converts the output values from signed to unsigned by adding the offset = 1 << (output_I-1)
170  //these values can be then directly used as inputs of the next LUT layer
172  for (unsigned int iOut = 0; iOut < lutOutSumArray.size(); iOut++) {
173  outputArray[iOut] = lutOutSumArray[iOut] + outOffset;
174  }
175 
176  return outputArray;
177  }
178 
179  auto getName() { return name; }
180 
181  private:
183  std::array<ap_ufixed<output_W, output_I, AP_TRN, AP_SAT>, neurons> outputArray;
184 
185  ap_uint<output_I> outOffset = 1 << (output_I - 1);
186 
187  std::array<std::array<std::array<ap_fixed<lut_W, lut_I>, lutSize>, neurons>, inputSize>
188  lutArray; //[inputNum][outputNum = neuronNum][address]
189 
191  };
192 
193 } /* namespace lutNN */
194 
195 #endif /* L1Trigger_L1TMuonOverlapPhase2_LutNeuronlayerFixedPoint_h */
std::array< ap_ufixed< input_W, input_I, AP_TRN, AP_SAT >, inputSize > inputArrayType
#define PUT_VAR(tree, keyPath, var)
constexpr size_t floorlog2(size_t i)
Derivative< X, A >::type derivative(const A &_)
Definition: Derivative.h:18
std::array< ap_fixed< lutOutSum_W, lutOutSum_I >, neurons > lutSumArrayType
lutSumArrayType & runWithInterpolation(const inputArrayType &inputArray)
void setLutArray(const std::array< std::array< std::array< ap_fixed< output_W, output_I >, lutSize >, neurons >, inputSize > &lutArray)
static std::string to_string(const XMLCh *ch)
#define LogTrace(id)
void load(boost::property_tree::ptree &tree, std::string keyPath)
static constexpr int input_I
std::array< ap_ufixed< output_W, output_I, AP_TRN, AP_SAT >, neurons > outputArray
std::array< std::array< std::array< ap_fixed< lut_W, lut_I >, lutSize >, neurons >, inputSize > lutArray
static constexpr int input_F
void save(boost::property_tree::ptree &tree, std::string keyPath)
double a
Definition: hdecay.h:121
#define CHECK_VAR(tree, keyPath, var)
Definition: tree.py:1
constexpr size_t ceillog2(size_t i)
#define str(s)