Belle II Software development
GRLNeuro.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <framework/logging/Logger.h>
10#include <trg/grl/GRLNeuro.h>
11#include <trg/grl/dataobjects/GRLMLP.h>
12#include <cdc/geometry/CDCGeometryPar.h>
13#include <framework/gearbox/Const.h>
14#include <framework/gearbox/Unit.h>
15#include <framework/datastore/StoreObjPtr.h>
16#include <framework/datastore/StoreArray.h>
17#include <trg/cdc/dbobjects/CDCTriggerNeuroConfig.h>
18#include <trg/cdc/dataobjects/CDCTriggerTrack.h>
19#include <string>
20#include <cmath>
21#include <TFile.h>
22#include <algorithm>
23#include <iomanip>
24#include <iostream>
25#include <vector>
26#include <array>
27#include <cstdint>
28#include <utility>
29using namespace Belle2;
30using namespace CDC;
31using namespace std;
32
33
34
35// ========== ap_(u)fixed ========
36
59inline float sim_ap_fixed(float val, int total_bits, int int_bits,
60 bool is_signed = true,
61 int quant_mode = 0,
62 int overflow_mode = 0,
63 int saturation_bits = 0)
64{
65 //for normal ap_types
66 if (total_bits >= int_bits) {
67
68 // Effective bits (handle saturation_bits and total_bits < int_bits cases)
69 int effective_total = (saturation_bits > 0) ?
70 std::min(saturation_bits, total_bits) : total_bits;
71 int effective_I = std::min(int_bits, effective_total);
72 int F = effective_total - effective_I; // Fractional bits ≥ 0
73 if (int_bits == 0 && is_signed == true) {
74 F = total_bits ;
75 effective_I = total_bits + 1;
76 }
77
78 // --- 2. Fast Scale Calculation (2^F) ---
79 const float scale = [F]() {
80 if (F <= 0) {return 1.0f;} // No fractional bits
81 else {
82 // Bit-shift is faster than std::pow(2, F)
83 const uint32_t scale_int = 1U << F;
84 return 1.0f / static_cast<float>(scale_int);
85 }
86 }();
87
88 // --- 3. Quantization (Mode-Specific Rounding) ---
89 const auto quantize = [](float scaled_val, int mode) -> int64_t {
90 using QuantizerFuncPtr = int64_t(*)(float);
91 static constexpr QuantizerFuncPtr quantizers[] = {
92 [](float x) -> int64_t { return static_cast<int64_t>(std::floor(x)); },
93 [](float x) -> int64_t { return static_cast<int64_t>(std::floor(x + 0.5f)); },
94 [](float x) -> int64_t {
95 return (x >= 0) ? static_cast<int64_t>(std::floor(x))
96 : static_cast<int64_t>(std::ceil(x));
97 },
98 [](float x) -> int64_t { return static_cast<int64_t>(std::floor(x)); },
99 [](float x) -> int64_t { return static_cast<int64_t>(std::ceil(x)); },
100 [](float x) -> int64_t { return llrint(x); }
101 };
102 const int clamped_mode = std::clamp(mode, 0, static_cast<int>(sizeof(quantizers) / sizeof(quantizers[0]) - 1));
103 return quantizers[clamped_mode](scaled_val);
104 };
105
106 int64_t fixed_val = quantize(val / scale, quant_mode);
107
108 // --- 4. Dynamic Range Calculation ---
109 const auto [min_val, max_val] = [ = ]() -> std::pair<int64_t, int64_t> {
110 if (is_signed)
111 {
112 const int64_t int_max = (1LL << (effective_I - 1)) - 1;
113 const int64_t int_min = -(1LL << (effective_I - 1));
114 const int64_t frac_mask = (F > 0) ? ((1LL << F) - 1) : 0;
115 return {int_min << F, (int_max << F) | frac_mask};
116 } else
117 {
118 const int64_t int_max = (1LL << effective_I) - 1;
119 const int64_t frac_mask = (F > 0) ? ((1LL << F) - 1) : 0;
120 return {0, (int_max << F) | frac_mask};
121 }
122 }();
123
124
125 // --- 5. Overflow Handling ---
126 const auto handle_overflow = [&]() {
127 const int64_t bit_mask = (1LL << effective_total) - 1;
128 const int64_t sign_bit = 1LL << (effective_total - 1);
129
130 switch (overflow_mode) {
131 case 0: // AP_SAT: Clamp to [min_val, max_val]
132 fixed_val = std::clamp(fixed_val, min_val, max_val);
133 break;
134
135 case 1: // AP_SAT_ZERO: Set to 0 on overflow
136 if (fixed_val > max_val || fixed_val < min_val) fixed_val = 0;
137 break;
138
139 case 2: // AP_WRAP: Modular wrap-around
140 if (is_signed) {
141 fixed_val = (fixed_val & bit_mask);
142 if (fixed_val & sign_bit) {
143 fixed_val -= (1LL << effective_total);
144 }
145 } else {
146 fixed_val &= bit_mask;
147 }
148 break;
149
150 case 3: // AP_WRAP_SM: Sign-magnitude wrap
151 if (is_signed) {
152 const int64_t magnitude_mask = (1LL << (effective_total - 1)) - 1;
153 const bool is_negative = (fixed_val < 0);
154 fixed_val = std::abs(fixed_val) & magnitude_mask;
155 if (is_negative) fixed_val = -fixed_val;
156 } else {
157 fixed_val &= bit_mask;
158 }
159 break;
160
161 case 4: // AP_SAT_SYM: Symmetric saturation
162 if (is_signed) {
163 const int64_t sym_limit = std::min(max_val, -min_val);
164 fixed_val = std::clamp(fixed_val, -sym_limit, sym_limit);
165 } else {
166 fixed_val = std::min(fixed_val, max_val);
167 }
168 break;
169
170 default: // Default to AP_WRAP
171 fixed_val &= bit_mask;
172 if (is_signed && (fixed_val & sign_bit)) {
173 fixed_val -= (1LL << effective_total);
174 }
175 }
176 };
177 handle_overflow();
178
179 // --- 6. Final Conversion ---
180 return static_cast<float>(fixed_val) * scale;
181 }
182 // for total_bits < int_bits case (e.g., ap_fixed<8,11>)
183 else {
184 // When W < I, the ap_fixed value has negative fractional bits.
185 // Firmware behavior is: quantize val / 2^(I-W), wrap that W-bit integer,
186 // then multiply back by 2^(I-W).
187 const int shift_amount = int_bits - total_bits;
188 const float scale = std::ldexp(1.0f, shift_amount);
189
190 const auto quantize = [](float scaled_val, int mode) -> int64_t {
191 switch (mode)
192 {
193 case 0: // AP_TRN
194 return static_cast<int64_t>(std::floor(scaled_val));
195 case 1: // AP_RND
196 return static_cast<int64_t>(std::floor(scaled_val + 0.5f));
197 case 2: // AP_RND_ZERO
198 return (scaled_val >= 0) ? static_cast<int64_t>(std::floor(scaled_val))
199 : static_cast<int64_t>(std::ceil(scaled_val));
200 case 3: // AP_RND_MIN_INF
201 return static_cast<int64_t>(std::floor(scaled_val));
202 case 4: // AP_RND_INF
203 return static_cast<int64_t>(std::ceil(scaled_val));
204 case 5: // AP_RND_CONV
205 return llrint(scaled_val);
206 default:
207 return static_cast<int64_t>(std::trunc(scaled_val));
208 }
209 };
210
211 int64_t fixed_val = quantize(val / scale, quant_mode);
212 const int64_t mask = (1LL << total_bits) - 1;
213
214 if (overflow_mode == 2) { // AP_WRAP
215 fixed_val &= mask;
216 if (is_signed) {
217 const int64_t sign_bit = 1LL << (total_bits - 1);
218 if (fixed_val & sign_bit) {
219 fixed_val -= (1LL << total_bits);
220 }
221 }
222 } else {
223 const int64_t min_val = is_signed ? -(1LL << (total_bits - 1)) : 0;
224 const int64_t max_val = is_signed ? ((1LL << (total_bits - 1)) - 1) : ((1LL << total_bits) - 1);
225 if (overflow_mode == 1 && (fixed_val < min_val || fixed_val > max_val)) {
226 fixed_val = 0;
227 } else {
228 fixed_val = std::clamp(fixed_val, min_val, max_val);
229 }
230 }
231
232 return static_cast<float>(fixed_val) * scale;
233 }
234}
235
236// --- Direct sim_ap_fixed calls for firmware compatibility ---
237// Parameters from firmware/defines.h:
238// input_layer_t: ap_fixed<13,13>
239// dense_0_iq_t: ap_fixed<12,13>
240// dense_0_weight_t: ap_fixed<9,4>
241// dense_0_accum_t: ap_fixed<18,16>
242// dense_0_t: ap_fixed<16,16>
243// dense_0_relu_t: ap_fixed<14,14>
244// dense_5_iq_t: ap_ufixed<13,8>
245// result_t: ap_fixed<19,10>
246// quant_mode: 0=trunc, 1=round
247// overflow_mode: 2=wrap, 4=AP_SAT_SYM
248
249
250void
252{
253 using std::vector;
254
255 // ------------------------------------------------------------------
256 // Basic parameter validation (fatal in initialize)
257 // ------------------------------------------------------------------
258
259 if (p.nHidden.size() != 1 && p.nHidden.size() != p.nMLP) {
260 B2FATAL("Number of nHidden lists should be 1 or " << p.nMLP);
261 }
262
263 if (p.outputScale.size() != 1 && p.outputScale.size() != p.nMLP) {
264 B2FATAL("Number of outputScale lists should be 1 or " << p.nMLP);
265 }
266
267 unsigned short nTarget = static_cast<unsigned short>(p.targetresult);
268 if (nTarget < 1) {
269 B2FATAL("No outputs! Turn on targetresult.");
270 }
271
272 for (unsigned iScale = 0; iScale < p.outputScale.size(); ++iScale) {
273 if (p.outputScale.at(iScale).size() != 2 * nTarget) {
274 B2FATAL("outputScale should be exactly " << 2 * nTarget << " values");
275 }
276 }
277
278 // ------------------------------------------------------------------
279 // Comprehensive parameter-size validation
280 // ------------------------------------------------------------------
281
282 auto check_size = [&](const auto & v, const char* name) {
283 const size_t s = v.size();
284 if (s != 1 && s != static_cast<size_t>(p.nMLP)) {
285 B2FATAL(std::string(name) + " size (" + std::to_string(s)
286 + ") != 1 and != nMLP (" + std::to_string(p.nMLP) + ")");
287 }
288 };
289
290 // sector / structure parameters
291 check_size(p.i_cdc_sector, "i_cdc_sector");
292 check_size(p.i_ecl_sector, "i_ecl_sector");
293 check_size(p.nHidden, "nHidden");
294 check_size(p.outputScale, "outputScale");
295
296 // bias
297 check_size(p.total_bit_bias, "total_bit_bias");
298 check_size(p.int_bit_bias, "int_bit_bias");
299 check_size(p.is_signed_bias, "is_signed_bias");
300 check_size(p.rounding_bias, "rounding_bias");
301 check_size(p.saturation_bias, "saturation_bias");
302
303 // accumulator
304 check_size(p.total_bit_accum, "total_bit_accum");
305 check_size(p.int_bit_accum, "int_bit_accum");
306 check_size(p.is_signed_accum, "is_signed_accum");
307 check_size(p.rounding_accum, "rounding_accum");
308 check_size(p.saturation_accum, "saturation_accum");
309
310 // weights
311 check_size(p.total_bit_weight, "total_bit_weight");
312 check_size(p.int_bit_weight, "int_bit_weight");
313 check_size(p.is_signed_weight, "is_signed_weight");
314 check_size(p.rounding_weight, "rounding_weight");
315 check_size(p.saturation_weight, "saturation_weight");
316
317 // relu
318 check_size(p.total_bit_relu, "total_bit_relu");
319 check_size(p.int_bit_relu, "int_bit_relu");
320 check_size(p.is_signed_relu, "is_signed_relu");
321 check_size(p.rounding_relu, "rounding_relu");
322 check_size(p.saturation_relu, "saturation_relu");
323
324 // generic
325 check_size(p.total_bit, "total_bit");
326 check_size(p.int_bit, "int_bit");
327 check_size(p.is_signed, "is_signed");
328 check_size(p.rounding, "rounding");
329 check_size(p.saturation, "saturation");
330
331 // inputs
332 check_size(p.W_input, "W_input");
333 check_size(p.I_input, "I_input");
334 check_size(p.W_input_layer, "W_input_layer");
335 check_size(p.I_input_layer, "I_input_layer");
336
337 // ------------------------------------------------------------------
338 // Initialize MLPs
339 // ------------------------------------------------------------------
340
341 m_MLPs.clear();
342 m_MLPs.reserve(p.nMLP);
343
344 for (unsigned iMLP = 0; iMLP < p.nMLP; ++iMLP) {
345
346 // helper: broadcast if size == 1
347 auto pick = [&](const auto & container) -> const auto& {
348 return (container.size() == 1) ? container.at(0) : container.at(iMLP);
349 };
350
351 unsigned short i_cdc = static_cast<unsigned short>(pick(p.i_cdc_sector));
352 unsigned short i_ecl = static_cast<unsigned short>(pick(p.i_ecl_sector));
353 unsigned short nInput = static_cast<unsigned short>(i_cdc + i_ecl);
354
355 // nHidden: vector<vector<float>>
356 const vector<float>& nhidden = pick(p.nHidden);
357 vector<unsigned short> nNodes = { nInput };
358
359 for (unsigned iHid = 0; iHid < nhidden.size(); ++iHid) {
360 if (p.multiplyHidden) {
361 nNodes.push_back(static_cast<unsigned short>(nhidden.at(iHid) * nNodes.at(0)));
362 } else {
363 nNodes.push_back(static_cast<unsigned short>(nhidden.at(iHid)));
364 }
365 }
366
367 nNodes.push_back(nTarget);
368 unsigned short targetVars = static_cast<unsigned short>(p.targetresult);
369
370 const vector<float>& outputScale = pick(p.outputScale);
371
372 GRLMLP grlmlp_temp(nNodes, targetVars, outputScale);
373
374 // bias
375 grlmlp_temp.set_total_bit_bias(pick(p.total_bit_bias));
376 grlmlp_temp.set_int_bit_bias(pick(p.int_bit_bias));
377 grlmlp_temp.set_is_signed_bias(pick(p.is_signed_bias));
378 grlmlp_temp.set_rounding_bias(pick(p.rounding_bias));
379 grlmlp_temp.set_saturation_bias(pick(p.saturation_bias));
380
381 // accumulator
382 grlmlp_temp.set_total_bit_accum(pick(p.total_bit_accum));
383 grlmlp_temp.set_int_bit_accum(pick(p.int_bit_accum));
384 grlmlp_temp.set_is_signed_accum(pick(p.is_signed_accum));
385 grlmlp_temp.set_rounding_accum(pick(p.rounding_accum));
386 grlmlp_temp.set_saturation_accum(pick(p.saturation_accum));
387
388 // weights
389 grlmlp_temp.set_total_bit_weight(pick(p.total_bit_weight));
390 grlmlp_temp.set_int_bit_weight(pick(p.int_bit_weight));
391 grlmlp_temp.set_is_signed_weight(pick(p.is_signed_weight));
392 grlmlp_temp.set_rounding_weight(pick(p.rounding_weight));
393 grlmlp_temp.set_saturation_weight(pick(p.saturation_weight));
394
395 // relu
396 grlmlp_temp.set_total_bit_relu(pick(p.total_bit_relu));
397 grlmlp_temp.set_int_bit_relu(pick(p.int_bit_relu));
398 grlmlp_temp.set_is_signed_relu(pick(p.is_signed_relu));
399 grlmlp_temp.set_rounding_relu(pick(p.rounding_relu));
400 grlmlp_temp.set_saturation_relu(pick(p.saturation_relu));
401
402 // generic
403 grlmlp_temp.set_total_bit(pick(p.total_bit));
404 grlmlp_temp.set_int_bit(pick(p.int_bit));
405 grlmlp_temp.set_is_signed(pick(p.is_signed));
406 grlmlp_temp.set_rounding(pick(p.rounding));
407 grlmlp_temp.set_saturation(pick(p.saturation));
408
409 // inputs
410 grlmlp_temp.set_W_input(pick(p.W_input));
411 grlmlp_temp.set_I_input(pick(p.I_input));
412 // input layer quantization parameters
413 grlmlp_temp.set_W_input_layer(pick(p.W_input_layer));
414 grlmlp_temp.set_I_input_layer(pick(p.I_input_layer));
415
416 m_MLPs.push_back(std::move(grlmlp_temp));
417 }
418}
419
420
421
422std::vector<float>
423GRLNeuro::runMLP(unsigned isector, const std::vector<float>& input)
424{
425 const GRLMLP& expert = m_MLPs.at(isector);
426 vector<float> weights = expert.get_weights();
427 vector<float> bias = expert.get_bias();
428 vector<int> total_bit_bias = expert.get_total_bit_bias();
429 vector<int> int_bit_bias = expert.get_int_bit_bias();
430 vector<bool> is_signed_bias = expert.get_is_signed_bias();
431 vector<int> rounding_bias = expert.get_rounding_bias();
432 vector<int> saturation_bias = expert.get_saturation_bias();
433 vector<int> total_bit_accum = expert.get_total_bit_accum();
434 vector<int> int_bit_accum = expert.get_int_bit_accum();
435 vector<bool> is_signed_accum = expert.get_is_signed_accum();
436 vector<int> rounding_accum = expert.get_rounding_accum();
437 vector<int> saturation_accum = expert.get_saturation_accum();
438 vector<int> total_bit_weight = expert.get_total_bit_weight();
439 vector<int> int_bit_weight = expert.get_int_bit_weight();
440 vector<bool> is_signed_weight = expert.get_is_signed_weight();
441 vector<int> rounding_weight = expert.get_rounding_weight();
442 vector<int> saturation_weight = expert.get_saturation_weight();
443 vector<int> total_bit_relu = expert.get_total_bit_relu();
444 vector<int> int_bit_relu = expert.get_int_bit_relu();
445 vector<bool> is_signed_relu = expert.get_is_signed_relu();
446 vector<int> rounding_relu = expert.get_rounding_relu();
447 vector<int> saturation_relu = expert.get_saturation_relu();
448 vector<int> total_bit = expert.get_total_bit();
449 vector<int> int_bit = expert.get_int_bit();
450 vector<bool> is_signed = expert.get_is_signed();
451 vector<int> rounding = expert.get_rounding();
452 vector<int> saturation = expert.get_saturation();
453 vector<vector<int>> W_input = expert.get_W_input();
454 vector<vector<int>> I_input = expert.get_I_input();
455 // Input layer quantization parameters
456 vector<vector<int>> W_input_layer = expert.get_W_input_layer();
457 vector<vector<int>> I_input_layer = expert.get_I_input_layer();
458
459 // Use actual input
460 vector<float> layerinput = input;
461
462 // Input layer quantization: firmware uses TWO steps:
463 // Step 1: float -> input_layer_t (ap_fixed<13,13>) with AP_RND, AP_SAT_SYM
464 // Step 2: input_layer_t -> dense_0_iq_t (per-input ap_fixed<W,I>) with AP_RND, AP_WRAP
465
466 // First, quantize raw input to input_layer_t (ap_fixed<13,13>)
467 // Firmware: ap_fixed<13,13> with AP_TRN (signed: floor toward -inf), AP_WRAP (defaults)
468 for (size_t i = 0; i < layerinput.size(); ++i) {
469 // AP_TRN for signed = floor (toward -inf), AP_WRAP
470 layerinput.at(i) = sim_ap_fixed(layerinput.at(i), 13, 13, true, 3, 2,
471 0); // signed, quant_mode=3 (floor), overflow_mode=2 (AP_WRAP)
472 }
473
474 // Use the first layer's W/I for input quantization (dense_0_iq)
475 const auto& w_layer = W_input_layer.at(0);
476 const auto& i_layer = I_input_layer.at(0);
477
478 // Step 2: dense_0_iq quantization with per-input W, I
479 for (size_t i = 0; i < layerinput.size(); ++i) {
480 // dense_0_iq quantization: signed, quant_mode=1 (AP_RND), overflow_mode=2 (AP_WRAP)
481 layerinput.at(i) = sim_ap_fixed(layerinput.at(i), w_layer.at(i), i_layer.at(i), true, 1, 2, 0);
482 }
483
484 //hidden layer and output layer
485 vector<float> layeroutput = {};
486 unsigned num_layers = expert.get_number_of_layers();
487
488 unsigned num_total_neurons = 0;
489 unsigned iw = 0;
490 for (unsigned iw_layer = 0; iw_layer < num_layers - 1; iw_layer++) {
491 //read bias
492 unsigned num_neurons = expert.get_number_of_nodes_layer(iw_layer + 1);
493 layeroutput.clear();
494 layeroutput.assign(num_neurons, 0.);
495 layeroutput.shrink_to_fit();
496
497
498 for (unsigned io = 0; io < num_neurons; ++io) {
499 float bias_raw = bias.at(io + num_total_neurons);
500 float bias_fixed = sim_ap_fixed(bias_raw, total_bit_bias.at(iw_layer), int_bit_bias.at(iw_layer), is_signed_bias.at(iw_layer),
501 rounding_bias.at(iw_layer), saturation_bias.at(iw_layer), 0);
502 float bias_contrib = sim_ap_fixed(bias_fixed, total_bit_accum.at(iw_layer), int_bit_accum.at(iw_layer),
503 is_signed_accum.at(iw_layer),
504 rounding_accum.at(iw_layer), saturation_accum.at(iw_layer), 0);
505 layeroutput.at(io) = bias_contrib;
506 }
507 num_total_neurons += num_neurons;
508
509 //input*weight
510 unsigned num_inputs = layerinput.size();
511
512 for (unsigned ii = 0; ii < num_inputs; ++ii) {
513 float input_val = layerinput.at(ii);
514 for (unsigned io = 0; io < num_neurons; ++io) {
515 float weight_raw = weights.at(iw);
516 float weight_fixed = sim_ap_fixed(weight_raw, total_bit_weight.at(iw_layer), int_bit_weight.at(iw_layer),
517 is_signed_weight.at(iw_layer),
518 rounding_weight.at(iw_layer), saturation_weight.at(iw_layer), 0);
519 float product = input_val * weight_fixed;
520 float contrib = sim_ap_fixed(product, total_bit_accum.at(iw_layer), int_bit_accum.at(iw_layer), is_signed_accum.at(iw_layer),
521 rounding_accum.at(iw_layer), saturation_accum.at(iw_layer), 0);
522 layeroutput.at(io) = sim_ap_fixed(layeroutput.at(io) + contrib, total_bit_accum.at(iw_layer), int_bit_accum.at(iw_layer),
523 is_signed_accum.at(iw_layer), rounding_accum.at(iw_layer), saturation_accum.at(iw_layer), 0);
524 ++iw;
525 }
526 }
527 // input*weight done
528
529 if (iw_layer < num_layers - 2) {
530 //relu
531 for (unsigned io = 0; io < num_neurons; ++io) {
532 float fixed_val = sim_ap_fixed(layeroutput.at(io), total_bit.at(iw_layer), int_bit.at(iw_layer), is_signed.at(iw_layer), 0,
533 saturation.at(iw_layer), 0);
534 float relu_val = (fixed_val > 0) ? fixed_val : 0;
535 layeroutput.at(io) = sim_ap_fixed(relu_val, total_bit_relu.at(iw_layer), int_bit_relu.at(iw_layer), is_signed_relu.at(iw_layer),
536 rounding_relu.at(iw_layer), saturation_relu.at(iw_layer), 0);
537 }
538 //input to next layer
539 layerinput.clear();
540 layerinput.assign(num_neurons, 0);
541 layerinput.shrink_to_fit();
542
543 for (unsigned i = 0; i < num_neurons; ++i) {
544 // firmware: use ap_fixed with parameters from W_input/I_input
545 // quant_mode=1 (AP_RND), overflow_mode=2 (AP_WRAP)
546 // W=0 means this input is zeroed (sparse quantization)
547 if (W_input.at(iw_layer).at(i) == 0) {
548 layerinput.at(i) = 0.0f;
549 } else {
550 const bool iq_is_signed = (iw_layer != 3); // dense_4_iq is ap_ufixed
551 layerinput.at(i) = sim_ap_fixed(layeroutput.at(i), W_input.at(iw_layer).at(i), I_input.at(iw_layer).at(i), iq_is_signed, 1, 2, 0);
552 }
553 }
554 } else {
555 // Final output layer - return all 10 outputs
556 // firmware: result_t is ap_fixed<19,10> with default AP_TRN (signed floor), AP_WRAP
557 vector<float> final_output(10, 0.0f);
558 for (unsigned io = 0; io < 10; ++io) {
559 final_output.at(io) = sim_ap_fixed(layeroutput.at(io), 19, 10, true, 3, 2, 0);
560 }
561 return final_output;
562 }
563 }
564
565 return vector<float>(10, 0.0f);
566}
567
568
569bool GRLNeuro::load(unsigned isector, const string& weightfilename, const string& biasfilename)
570{
571 if (weightfilename.size() < 1) {
572 B2ERROR("Could not load Neurotrigger weights from database!");
573 return false;
574 } else if (biasfilename.size() < 1) {
575 B2ERROR("Could not load Neurotrigger bias from database!");
576 return false;
577 } else {
578 std::ifstream wfile(weightfilename);
579 if (!wfile.is_open()) {
580 B2WARNING("Could not open file " << weightfilename);
581 return false;
582 } else {
583 std::ifstream bfile(biasfilename);
584 if (!bfile.is_open()) {
585 B2WARNING("Could not open file " << biasfilename);
586 return false;
587 } else {
588 GRLMLP& expert = m_MLPs.at(isector);
589 std::vector<float> warray;
590 std::vector<float> barray;
591 warray.clear();
592 barray.clear();
593
594 float element;
595 while (wfile >> element) {
596 warray.push_back(element);
597 }
598 while (bfile >> element) {
599 barray.push_back(element);
600 }
601
602 if (warray.size() != expert.n_weights_cal()) {
603 B2ERROR("Number of weights is not equal to registered architecture!");
604 return false;
605 } else expert.set_weights(warray);
606 if (barray.size() != expert.n_bias_cal()) {
607 B2ERROR("Number of bias is not equal to registered architecture!");
608 return false;
609 }
610
611 expert.set_weights(warray);
612 expert.set_bias(barray);
613 return true;
614 }
615 }
616 }
617}
618
619bool GRLNeuro::load(unsigned isector, std::vector<float> warray, std::vector<float> barray)
620{
621 GRLMLP& expert = m_MLPs.at(isector);
622 expert.set_weights(warray);
623 expert.set_bias(barray);
624 return true;
625}
Class to keep all parameters of an expert MLP for the neuro trigger.
Definition GRLMLP.h:21
void set_W_input_layer(const std::vector< std::vector< int > > &i)
Input layer quantization parameters.
Definition GRLMLP.h:120
void set_total_bit_bias(const std::vector< int > &i)
set bit width etc.
Definition GRLMLP.h:92
void initialize(const Parameters &p)
Set parameters and get some network independent parameters.
Definition GRLNeuro.cc:251
bool load(unsigned isector, const std::string &wfilename, const std::string &bfilename)
Load MLPs from file.
Definition GRLNeuro.cc:569
std::vector< GRLMLP > m_MLPs
List of networks.
Definition GRLNeuro.h:144
std::vector< float > runMLP(unsigned isector, const std::vector< float > &input)
Run an expert MLP.
Definition GRLNeuro.cc:423
Abstract base class for different kinds of events.
STL namespace.
Struct to keep neurotrigger parameters.
Definition GRLNeuro.h:40