Belle II Software  release-08-01-10
GRLNeuroTrainerModule.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 "trg/grl/modules/trggrlneuralnet/GRLNeuroTrainerModule.h"
10 #ifdef HAS_OPENMP
11 #include <parallel_fann.hpp>
12 #else
13 #include <fann.h>
14 #endif
15 
16 #include <framework/datastore/StoreArray.h>
17 #include <framework/datastore/StoreObjPtr.h>
18 #include <mdst/dataobjects/MCParticle.h>
19 #include <tracking/dataobjects/RecoTrack.h>
20 #include <framework/datastore/StoreObjPtr.h>
21 #include <framework/dataobjects/EventMetaData.h>
22 #include <framework/core/ModuleParam.templateDetails.h>
23 #include <analysis/utility/PCmsLabTransform.h>
24 #include <trg/cdc/dataobjects/CDCTriggerTrack.h>
25 #include <trg/ecl/TrgEclMapping.h>
26 #include <trg/ecl/dataobjects/TRGECLCluster.h>
27 #include <trg/ecl/dataobjects/TRGECLTrg.h>
28 #include <mdst/dataobjects/SoftwareTriggerResult.h>
29 #include <trg/grl/dataobjects/GRLMLPData.h>
30 #include "trg/grl/dataobjects/TRGGRLUnpackerStore.h"
31 
32 #include <cdc/geometry/CDCGeometryPar.h>
33 #include <framework/gearbox/Unit.h>
34 
35 #include <fstream>
36 #include <cmath>
37 #include <TFile.h>
38 
39 using namespace Belle2;
40 using namespace std;
41 
42 //this line registers the module with the framework and actually makes it available
43 //in steering files or the the module list (basf2 -m).
44 REG_MODULE(GRLNeuroTrainer);
45 
47 {
49  "The NeuroTriggerTrainer module of the GRL.\n"
50  "Takes CDC track and ECL cluster to prepare input data\n"
51  "for the training of a neural network.\n"
52  "Networks are trained after the event loop and saved."
53  );
54  // parameters for saving / loading
55  addParam("TRGECLClusters", m_TrgECLClusterName,
56  "Name of the StoreArray holding the information of trigger ecl clusters ",
57  string("TRGECLClusters"));
58  addParam("2DfinderCollection", m_2DfinderCollectionName,
59  "Name of the StoreArray holding the tracks made by the 2D finder to be used as input.",
60  string("TRGCDC2DFinderTracks"));
61  addParam("GRLCollection", m_GRLCollectionName,
62  "Name of the StoreArray holding the tracks made by the GRL to be used as input.",
63  string("TRGGRLUnpackerStore"));
64  addParam("filename", m_filename,
65  "Name of the root file where the NeuroTrigger parameters will be saved.",
66  string("GRLNeuroTrigger.root"));
67  addParam("trainFilename", m_trainFilename,
68  "Name of the root file where the generated training samples will be saved.",
69  string("GRLNeuroTrigger.root"));
70  addParam("arrayname", m_arrayname,
71  "Name of the TObjArray to hold the NeuroTrigger parameters.",
72  string("MLPs"));
73  addParam("trainArrayname", m_trainArrayname,
74  "Name of the TObjArray to hold the training samples.",
75  string("trainSets"));
76  addParam("saveDebug", m_saveDebug,
77  "If true, save parameter distribution of training data "
78  "in train file and training curve in log file.", true);
79  addParam("load", m_load,
80  "Switch to load saved parameters if existing. "
81  "Take care not to duplicate training sets!", false);
82  // NeuroTrigger parameters
83  addParam("nMLP", m_parameters.nMLP,
84  "Number of expert MLPs.", m_parameters.nMLP);
85  addParam("n_cdc_sector", m_parameters.n_cdc_sector,
86  "Number of expert CDC MLPs.", m_parameters.n_cdc_sector);
87  addParam("n_ecl_sector", m_parameters.n_ecl_sector,
88  "Number of expert ECL MLPs.", m_parameters.n_ecl_sector);
89  addParam("i_cdc_sector", m_parameters.i_cdc_sector,
90  "#cdc track of expert MLPs.", m_parameters.i_cdc_sector);
91  addParam("i_ecl_sector", m_parameters.i_ecl_sector,
92  "#ecl cluster of expert MLPs.", m_parameters.i_ecl_sector);
93  addParam("nHidden", m_parameters.nHidden,
94  "Number of nodes in each hidden layer for all networks "
95  "or factor to multiply with number of inputs (1 list or nMLP lists). "
96  "The number of layers is derived from the shape.", m_parameters.nHidden);
97  addParam("multiplyHidden", m_parameters.multiplyHidden,
98  "If true, multiply nHidden with number of input nodes.",
100  addParam("outputScale", m_parameters.outputScale,
101  "Output scale for all networks (1 value list or nMLP value lists). "
102  "Output[i] of the MLP is scaled from [-1, 1] "
103  "to [outputScale[2*i], outputScale[2*i+1]]. "
104  "(units: z[cm] / theta[degree])", m_parameters.outputScale);
105  addParam("nTrainMin", m_nTrainMin,
106  "Minimal number of training samples "
107  "or factor to multiply with number of weights. "
108  "If the minimal number of samples is not reached, "
109  "all samples are saved but no training is started.", 10.);
110  addParam("nTrainMax", m_nTrainMax,
111  "Maximal number of training samples "
112  "or factor to multiply with number of weights. "
113  "When the maximal number of samples is reached, "
114  "no further samples are added.", 10.);
115  addParam("multiplyNTrain", m_multiplyNTrain,
116  "If true, multiply nTrainMin and nTrainMax with number of weights.",
117  true);
118  addParam("nValid", m_nValid,
119  "Number of validation samples for training.", 1000);
120  addParam("nTest", m_nTest,
121  "Number of test samples to get resolution after training.", 5000);
122  addParam("wMax", m_wMax,
123  "Weights are limited to [-wMax, wMax] after each training epoch "
124  "(for convenience of the FPGA implementation).",
125  63.);
126  addParam("nThreads", m_nThreads,
127  "Number of threads for parallel training.", 1);
128  addParam("checkInterval", m_checkInterval,
129  "Training is stopped if validation error is higher than "
130  "checkInterval epochs ago, i.e. either the validation error is increasing "
131  "or the gain is less than the fluctuations.", 500);
132  addParam("maxEpochs", m_maxEpochs,
133  "Maximum number of training epochs.", 10000);
134  addParam("repeatTrain", m_repeatTrain,
135  "If >1, training is repeated several times with different start weights. "
136  "The weights which give the best resolution on the test samples are kept.", 1);
137 }
138 
139 
140 void
142 {
143  //initialize with input parameter
148  m_trainSets.clear();
149  for (unsigned iMLP = 0; iMLP < (unsigned)n_sector; ++iMLP) {
150  m_trainSets.push_back(GRLMLPData());
151  scale_bg.push_back(0);
152  }
153  if (m_nTrainMin > m_nTrainMax) {
155  B2WARNING("nTrainMin set to " << m_nTrainMin << " (was larger than nTrainMax)");
156  }
157 
158  //initializa histograms
159  for (int isector = 0; isector < n_sector; isector++) {
160  h_cdc2d_phi_sig .push_back(new TH1D(("h_cdc2d_phi_sig_" + to_string(isector)).c_str(),
161  ("h_cdc2d_phi_sig_" + to_string(isector)).c_str(), 64, -3.2, 3.2));
162  h_cdc2d_pt_sig .push_back(new TH1D(("h_cdc2d_pt_sig_" + to_string(isector)).c_str(),
163  ("h_cdc2d_pt_sig_" + to_string(isector)).c_str(), 100, -5, 5));
164  h_selTheta_sig.push_back(new TH1D(("h_selTheta_sig_" + to_string(isector)).c_str(),
165  ("h_selTheta_sig_" + to_string(isector)).c_str(), 64, -3.2, 3.2));
166  h_selPhi_sig .push_back(new TH1D(("h_selPhi_sig_" + to_string(isector)).c_str(), ("h_selPhi_sig_" + to_string(isector)).c_str(),
167  64, -3.2, 3.2));
168  h_selE_sig .push_back(new TH1D(("h_selE_sig_" + to_string(isector)).c_str(), ("h_selE_sig_" + to_string(isector)).c_str(),
169  100, 0, 10));
170  h_result_sig .push_back(new TH1D(("h_result_sig_" + to_string(isector)).c_str(), ("h_result_sig_" + to_string(isector)).c_str(),
171  100, -1, 1));
172  h_cdc2d_phi_bg .push_back(new TH1D(("h_cdc2d_phi_bg_" + to_string(isector)).c_str(),
173  ("h_cdc2d_phi_bg_" + to_string(isector)).c_str(), 64, -3.2, 3.2));
174  h_cdc2d_pt_bg .push_back(new TH1D(("h_cdc2d_pt_bg_" + to_string(isector)).c_str(),
175  ("h_cdc2d_pt_bg_" + to_string(isector)).c_str(), 100, -5, 5));
176  h_selTheta_bg .push_back(new TH1D(("h_selTheta_bg_" + to_string(isector)).c_str(), ("h_selTheta_bg_" + to_string(isector)).c_str(),
177  64, -3.2, 3.2));
178  h_selPhi_bg .push_back(new TH1D(("h_selPhi_bg_" + to_string(isector)).c_str(), ("h_selPhi_bg_" + to_string(isector)).c_str(),
179  64, -3.2, 3.2));
180  h_selE_bg .push_back(new TH1D(("h_selE_bg_" + to_string(isector)).c_str(), ("h_selE_bg_" + to_string(isector)).c_str(),
181  100, 0, 10));
182  h_result_bg .push_back(new TH1D(("h_result_bg_" + to_string(isector)).c_str(), ("h_result_bg_" + to_string(isector)).c_str(),
183  100, -1, 1));
184  }
185  h_ncdcf_sig.push_back(new TH1D("h_ncdcf_sig", "h_ncdcf_sig", 10, 0, 10));
186  h_ncdcs_sig.push_back(new TH1D("h_ncdcs_sig", "h_ncdcs_sig", 10, 0, 10));
187  h_ncdci_sig.push_back(new TH1D("h_ncdci_sig", "h_ncdci_sig", 10, 0, 10));
188  h_ncdc_sig.push_back(new TH1D("h_ncdc_sig", "h_ncdc_sig", 10, 0, 10));
189  h_necl_sig.push_back(new TH1D("h_necl_sig", "h_necl_sig", 10, 0, 10));
190  h_ncdcf_bg.push_back(new TH1D("h_ncdcf_bg", "h_ncdcf_bg", 10, 0, 10));
191  h_ncdcs_bg.push_back(new TH1D("h_ncdcs_bg", "h_ncdcs_bg", 10, 0, 10));
192  h_ncdci_bg.push_back(new TH1D("h_ncdci_bg", "h_ncdci_bg", 10, 0, 10));
193  h_ncdc_bg.push_back(new TH1D("h_ncdc_bg", "h_ncdc_bg", 10, 0, 10));
194  h_necl_bg.push_back(new TH1D("h_necl_bg", "h_necl_bg", 10, 0, 10));
195 
196  //..Trigger ThetaID for each trigger cell. Could be replaced by getMaxThetaId() for newer MC
197  TrgEclMapping* trgecl_obj = new TrgEclMapping();
198  for (int tc = 1; tc <= 576; tc++) {
199  TCThetaID.push_back(trgecl_obj->getTCThetaIdFromTCId(tc));
200  }
201 
202  //-----------------------------------------------------------------------------------------
203  //..ECL look up tables
204  PCmsLabTransform boostrotate;
205  for (int tc = 1; tc <= 576; tc++) {
206 
207  //..Four vector of a 1 GeV lab photon at this TC
208  TVector3 CellPosition = trgecl_obj->getTCPosition(tc);
209  ROOT::Math::PxPyPzEVector CellLab;
210  CellLab.SetPx(CellPosition.Unit().Px());
211  CellLab.SetPy(CellPosition.Unit().Py());
212  CellLab.SetPz(CellPosition.Unit().Pz());
213  CellLab.SetE(1.);
214 
215  //..cotan Theta and phi in lab
216  TCPhiLab.push_back(CellPosition.Phi());
217  double tantheta = tan(CellPosition.Theta());
218  TCcotThetaLab.push_back(1. / tantheta);
219 
220  //..Corresponding 4 vector in the COM frame
221  ROOT::Math::PxPyPzEVector CellCOM = boostrotate.rotateLabToCms() * CellLab;
222  TCThetaCOM.push_back(CellCOM.Theta()*TMath::RadToDeg());
223  TCPhiCOM.push_back(CellCOM.Phi()*TMath::RadToDeg());
224 
225  //..Scale to give 1 GeV in the COM frame
226  TC1GeV.push_back(1. / CellCOM.E());
227  }
228 
229  delete trgecl_obj;
230 }
231 
232 void
234 {
235  //inputs and outputs
236  std::vector<float> input;
237  std::vector<float> output;
238 
240  std::vector<float> cdc2d_phi;
241  std::vector<float> cdc2d_pt;
242 
243  //GRL input
245  int n_cdcf = 0;
246  int n_cdcs = 0;
247  int n_cdci = 0;
248  int n_cdc = 0;
249  int map_cdcf[36];
250  int map_cdcs[36];
251  int map_cdci[36];
252  for (int i = 0; i < 36; i++) {
253  map_cdcf[i] = 0;
254  map_cdcs[i] = 0;
255  map_cdci[i] = 0;
256  }
257 
258  //full track
259  for (int i = 0; i < 36; i++) {
260  if (GRLStore->get_phi_CDC(i)) {
261  map_cdcf[i] = 1;
262  }
263  }
264 
265  //short track
266  for (int i = 0; i < 64; i++) {
267  if (GRLStore->get_map_ST2(i)) {
268  int j = i * (36. / 64.);
269  map_cdcs[j] = 1;
270  }
271  }
272 
273  //inner track
274  for (int i = 0; i < 64; i++) {
275  if (GRLStore->get_map_TSF0(i)) {
276  int j = i * (36. / 64.);
277  int j1 = i - 4;
278  if (j1 < 0) j1 = j1 + 64;
279  int j2 = i - 3;
280  if (j2 < 0) j2 = j2 + 64;
281  int j3 = i - 2;
282  if (j3 < 0) j3 = j3 + 64;
283  int j4 = i - 1;
284  if (j4 < 0) j4 = j4 + 64;
285  int j5 = i;
286  int j6 = i + 1;
287  if (j6 > 63) j6 = j6 - 64;
288  int j7 = i + 2;
289  if (j7 > 63) j7 = j7 - 64;
290  if (
291  (GRLStore->get_map_TSF1(j1) || GRLStore->get_map_TSF1(j2) || GRLStore->get_map_TSF1(j3) || GRLStore->get_map_TSF1(j4)
292  || GRLStore->get_map_TSF1(j5))
293  &&
294  (GRLStore->get_map_TSF2(j3) || GRLStore->get_map_TSF2(j4) || GRLStore->get_map_TSF2(j5) || GRLStore->get_map_TSF2(j6)
295  || GRLStore->get_map_TSF2(j7))
296  )
297  map_cdci[j] = 1;
298  }
299  }
300 
301  //avoid overlap
302  for (int i = 0; i < 36; i++) {
303  if (map_cdcf[i] == 1) {
304  int i1 = i - 2;
305  if (i1 < 0) i1 = i1 + 36;
306  int i2 = i - 1;
307  if (i2 < 0) i2 = i2 + 36;
308  int i3 = i;
309  int i4 = i + 1;
310  // cppcheck-suppress knownConditionTrueFalse
311  if (i4 > 36) i4 = i4 - 36;
312  int i5 = i + 2;
313  if (i5 > 36) i5 = i5 - 36;
314  //map_cdcs[i1]=0;
315  map_cdcs[i2] = 0;
316  map_cdcs[i3] = 0;
317  map_cdcs[i4] = 0;
318  //map_cdcs[i5]=0;
319  //map_cdci[i1]=0;
320  map_cdci[i2] = 0;
321  map_cdci[i3] = 0;
322  map_cdci[i4] = 0;
323  //map_cdci[i5]=0;
324  }
325  }
326  for (int i = 0; i < 36; i++) {
327  if (map_cdcs[i] == 1) {
328  int i1 = i - 2;
329  if (i1 < 0) i1 = i1 + 36;
330  int i2 = i - 1;
331  if (i2 < 0) i2 = i2 + 36;
332  int i3 = i;
333  int i4 = i + 1;
334  // cppcheck-suppress knownConditionTrueFalse
335  if (i4 > 36) i4 = i4 - 36;
336  int i5 = i + 2;
337  if (i5 > 36) i5 = i5 - 36;
338  //map_cdci[i1]=0;
339  map_cdci[i2] = 0;
340  map_cdci[i3] = 0;
341  map_cdci[i4] = 0;
342  //map_cdci[i5]=0;
343  }
344  }
345 
347  //for (int i = 0; i < 36; i++) {
348  // std::cout << map_cdcf[i] << " " ;
349  //}
350  //std::cout << std::endl;
351  //for (int i = 0; i < 36; i++) {
352  // std::cout << map_cdcs[i] << " " ;
353  //}
354  //std::cout << std::endl;
355  //for (int i = 0; i < 36; i++) {
356  // std::cout << map_cdci[i] << " " ;
357  //}
358  //std::cout << std::endl;
359 
360  //count
361  for (int i = 0; i < 36; i++) {
362  if (map_cdcf[i] == 1) {n_cdcf++; n_cdc++;}
363  if (map_cdcs[i] == 1) {n_cdcs++; n_cdc++;}
364  if (map_cdci[i] == 1) {n_cdci++; n_cdc++;}
365  }
366 
367  //input
368  for (int i = 0; i < 36; i++) {
369  input.push_back((map_cdcf[i] - 0.5) * 2);
370  }
371  for (int i = 0; i < 36; i++) {
372  input.push_back((map_cdcs[i] - 0.5) * 2);
373  }
374  for (int i = 0; i < 36; i++) {
375  input.push_back((map_cdci[i] - 0.5) * 2);
376  }
377 
378  //ECL input
379  //..Use only clusters within 100 ns of event timing (from ECL).
380  StoreArray<TRGECLTrg> trgArray;
382  int ntrgArray = trgArray.getEntries();
383  double EventTiming = -9999.;
384  if (ntrgArray > 0) {EventTiming = trgArray[0]->getEventTiming();}
385  std::vector<int> selTC;
386  std::vector<float> selTheta;
387  std::vector<float> selPhi;
388  std::vector<float> selE;
389  for (int ic = 0; ic < eclTrgClusterArray.getEntries(); ic++) {
390  double tcT = abs(eclTrgClusterArray[ic]->getTimeAve() - EventTiming);
391  //if (tcT < 100.) {
392  int TC = eclTrgClusterArray[ic]->getMaxTCId();
393  selTC.push_back(TC);
394  selTheta.push_back(TCcotThetaLab[TC - 1]);
395  selPhi.push_back(TCPhiLab[TC - 1]);
396  selE.push_back(eclTrgClusterArray[ic]->getEnergyDep() * 0.001);
397  input.push_back(TCcotThetaLab[TC - 1] / TMath::Pi());
398  input.push_back(TCPhiLab[TC - 1] / TMath::Pi());
399  input.push_back((eclTrgClusterArray[ic]->getEnergyDep() * 0.001 - 3.5) / 3.5);
400  //}
401  B2DEBUG(50, "InputECL " << ic << " " << tcT << " " << TC << " " << TCcotThetaLab[TC - 1] << " " << TCPhiLab[TC - 1] << " " <<
402  eclTrgClusterArray[ic]->getEnergyDep() << " " << EventTiming);
403  }
404 
405  //output
406  bool accepted_signal = false;
407  bool accepted_bg = false;
408  bool accepted_hadron = false;
409  bool accepted_filter = false;
410  bool accepted_bhabha = false;
412  if (result_soft.isValid()) {
413  const std::map<std::string, int>& skim_map = result_soft->getResults();
414  if (skim_map.find("software_trigger_cut&skim&accept_hadronb2") != skim_map.end()) {
415  accepted_hadron = (result_soft->getResult("software_trigger_cut&skim&accept_hadronb2") == SoftwareTriggerCutResult::c_accept);
416  }
417  if (skim_map.find("software_trigger_cut&filter&total_result") != skim_map.end()) {
418  accepted_filter = (result_soft->getResult("software_trigger_cut&filter&total_result") == SoftwareTriggerCutResult::c_accept);
419  }
420  if (skim_map.find("software_trigger_cut&skim&accept_bhabha") != skim_map.end()) {
421  accepted_bhabha = (result_soft->getResult("software_trigger_cut&skim&accept_bhabha") == SoftwareTriggerCutResult::c_accept);
422  }
423  }
424 
425  accepted_signal = accepted_hadron && accepted_filter;
426  accepted_bg = !accepted_filter;
427 
428  //input and output for NN training
429  int cdc_sector = cdc2d_phi.size();
430  int ecl_sector = selTC.size();
431  int isector = cdc_sector * n_ecl_sector + ecl_sector;
432  B2DEBUG(50, "Input " << cdc_sector << " " << ecl_sector << " " << accepted_signal << " " << accepted_bg);
433  if (accepted_signal
434  && !accepted_filter)B2DEBUG(50, "Input " << cdc_sector << " " << ecl_sector << " " << accepted_signal << " " << accepted_filter <<
435  " " << accepted_bhabha);
436 
437  if (accepted_signal) {
438  output.push_back(1);
439  } else if (accepted_bg) {
440  scale_bg[isector]++;
441  if (isector == 3) {
442  if (scale_bg[isector] == 100) {
443  output.push_back(-1);
444  scale_bg[isector] = 1;
445  } else return;
446  }
447  if (isector == 4) {
448  if (scale_bg[isector] == 5) {
449  output.push_back(-1);
450  scale_bg[isector] = 1;
451  } else return;
452  } else {
453  output.push_back(-1);
454  }
455  } else {
456  return;
457  }
458 
459 
460 
461  if (cdc_sector < n_cdc_sector && ecl_sector < n_ecl_sector) {
462  m_trainSets[isector].addSample(input, output);
463  if (m_saveDebug) {
464  if (accepted_signal) {
465  for (int i = 0; i < cdc_sector; i++) h_cdc2d_phi_sig[isector]->Fill(cdc2d_phi[i]);
466  for (int i = 0; i < cdc_sector; i++) h_cdc2d_pt_sig[isector]->Fill(cdc2d_pt[i]);
467  for (int i = 0; i < ecl_sector; i++) h_selTheta_sig[isector]->Fill(selTheta[i]);
468  for (int i = 0; i < ecl_sector; i++) h_selPhi_sig[isector]->Fill(selPhi[i]);
469  for (int i = 0; i < ecl_sector; i++) h_selE_sig[isector]->Fill(selE[i]);
470  h_ncdcf_sig[0]->Fill(n_cdcf);
471  h_ncdcs_sig[0]->Fill(n_cdcs);
472  h_ncdci_sig[0]->Fill(n_cdci);
473  h_ncdc_sig[0]->Fill(n_cdc);
474  h_necl_sig[0]->Fill(ecl_sector);
475  } else if (accepted_bg) {
476  for (int i = 0; i < cdc_sector; i++) h_cdc2d_phi_bg[isector]->Fill(cdc2d_phi[i]);
477  for (int i = 0; i < cdc_sector; i++) h_cdc2d_pt_bg[isector]->Fill(cdc2d_pt[i]);
478  for (int i = 0; i < ecl_sector; i++) h_selTheta_bg[isector]->Fill(selTheta[i]);
479  for (int i = 0; i < ecl_sector; i++) h_selPhi_bg[isector]->Fill(selPhi[i]);
480  for (int i = 0; i < ecl_sector; i++) h_selE_bg[isector]->Fill(selE[i]);
481  h_ncdcf_bg[0]->Fill(n_cdcf);
482  h_ncdcs_bg[0]->Fill(n_cdcs);
483  h_ncdci_bg[0]->Fill(n_cdci);
484  h_ncdc_bg[0]->Fill(n_cdc);
485  h_necl_bg[0]->Fill(ecl_sector);
486  }
487  }
488  }
489 }
490 
491 void
493 {
494  // do training for all sectors with sufficient training samples
495  for (unsigned isector = 0; isector < m_GRLNeuro.nSectors(); ++isector) {
496  // skip sectors that have already been trained
497  if (m_GRLNeuro[isector].isTrained())
498  continue;
499  float nTrainMin = m_multiplyNTrain ? m_nTrainMin * m_GRLNeuro[isector].getNumberOfWeights() : m_nTrainMin;
500  std::cout << m_nTrainMin << " " << m_nValid << " " << m_nTest << std::endl;
501  if (m_trainSets[isector].getNumberOfSamples() < (nTrainMin + m_nValid + m_nTest)) {
502  B2WARNING("Not enough training samples for sector " << isector << " (" << (nTrainMin + m_nValid + m_nTest)
503  << " requested, " << m_trainSets[isector].getNumberOfSamples() << " found)");
504  continue;
505  }
506  train(isector);
507  m_GRLNeuro[isector].Trained(true);
508  // save all networks (including the newly trained)
509  //m_GRLNeuro.save(m_filename, m_arrayname);
510  }
511 
512  // save the training data
514 }
515 
516 
517 
518 void
520 {
521 #ifdef HAS_OPENMP
522  B2INFO("Training network for sector " << isector << " with OpenMP");
523 #else
524  B2INFO("Training network for sector " << isector << " without OpenMP");
525 #endif
526  // initialize network
527  unsigned nLayers = m_GRLNeuro[isector].getNumberOfLayers();
528  unsigned* nNodes = new unsigned[nLayers];
529  for (unsigned il = 0; il < nLayers; ++il) {
530  nNodes[il] = m_GRLNeuro[isector].getNumberOfNodesLayer(il);
531  }
532  struct fann* ann = fann_create_standard_array(nLayers, nNodes);
533  // initialize training and validation data
534  GRLMLPData currentData = m_trainSets[isector];
535  // train set
536  unsigned nTrain = m_trainSets[isector].getNumberOfSamples() - m_nValid - m_nTest;
537  struct fann_train_data* train_data =
538  fann_create_train(nTrain, nNodes[0], nNodes[nLayers - 1]);
539  for (unsigned i = 0; i < nTrain; ++i) {
540  vector<float> input = currentData.getInput(i);
541  for (unsigned j = 0; j < input.size(); ++j) {
542  train_data->input[i][j] = input[j];
543  }
544  vector<float> target = currentData.getTarget(i);
545  for (unsigned j = 0; j < target.size(); ++j) {
546  train_data->output[i][j] = target[j];
547  }
548  }
549  // validation set
550  struct fann_train_data* valid_data =
551  fann_create_train(m_nValid, nNodes[0], nNodes[nLayers - 1]);
552  for (unsigned i = nTrain; i < nTrain + m_nValid; ++i) {
553  vector<float> input = currentData.getInput(i);
554  for (unsigned j = 0; j < input.size(); ++j) {
555  valid_data->input[i - nTrain][j] = input[j];
556  }
557  vector<float> target = currentData.getTarget(i);
558  for (unsigned j = 0; j < target.size(); ++j) {
559  valid_data->output[i - nTrain][j] = target[j];
560  }
561  }
562  // set network parameters
563  fann_set_activation_function_hidden(ann, FANN_SIGMOID_SYMMETRIC);
564  fann_set_activation_function_output(ann, FANN_SIGMOID_SYMMETRIC);
565  fann_set_training_algorithm(ann, FANN_TRAIN_RPROP);
566  // keep train error of optimum for all runs
567  vector<double> trainOptLog = {};
568  vector<double> validOptLog = {};
569  // repeat training several times with different random start weights
570  for (int irun = 0; irun < m_repeatTrain; ++irun) {
571  double bestValid = 999.;
572  vector<double> trainLog = {};
573  vector<double> validLog = {};
574  trainLog.assign(m_maxEpochs, 0.);
575  validLog.assign(m_maxEpochs, 0.);
576  int breakEpoch = 0;
577  int bestEpoch = 0;
578  vector<fann_type> bestWeights = {};
579  bestWeights.assign(m_GRLNeuro[isector].getNumberOfWeights(), 0.);
580  fann_randomize_weights(ann, -0.1, 0.1);
581  // train and save the network
582  for (int epoch = 1; epoch <= m_maxEpochs; ++epoch) {
583 #ifdef HAS_OPENMP
584  double mse = parallel_fann::train_epoch_irpropm_parallel(ann, train_data, m_nThreads);
585 #else
586  double mse = fann_train_epoch(ann, train_data);
587 #endif
588  trainLog[epoch - 1] = mse;
589  // reduce weights that got too large
590  for (unsigned iw = 0; iw < ann->total_connections; ++iw) {
591  if (ann->weights[iw] > m_wMax)
592  ann->weights[iw] = m_wMax;
593  else if (ann->weights[iw] < -m_wMax)
594  ann->weights[iw] = -m_wMax;
595  }
596  // evaluate validation set
597  fann_reset_MSE(ann);
598 #ifdef HAS_OPENMP
599  double valid_mse = parallel_fann::test_data_parallel(ann, valid_data, m_nThreads);
600 #else
601  double valid_mse = fann_test_data(ann, valid_data);
602 #endif
603  validLog[epoch - 1] = valid_mse;
604  // keep weights for lowest validation error
605  if (valid_mse < bestValid) {
606  bestValid = valid_mse;
607  for (unsigned iw = 0; iw < ann->total_connections; ++iw) {
608  bestWeights[iw] = ann->weights[iw];
609  }
610  bestEpoch = epoch;
611  }
612  // break when validation error increases
613  if (epoch > m_checkInterval && valid_mse > validLog[epoch - m_checkInterval]) {
614  B2INFO("Training run " << irun << " stopped in epoch " << epoch);
615  B2INFO("Train error: " << mse << ", valid error: " << valid_mse <<
616  ", best valid: " << bestValid);
617  breakEpoch = epoch;
618  break;
619  }
620  // print current status
621  if (epoch == 1 || (epoch < 100 && epoch % 10 == 0) || epoch % 100 == 0) {
622  B2INFO("Epoch " << epoch << ": Train error = " << mse <<
623  ", valid error = " << valid_mse << ", best valid = " << bestValid);
624  }
625  }
626  if (breakEpoch == 0) {
627  B2INFO("Training run " << irun << " finished in epoch " << m_maxEpochs);
628  breakEpoch = m_maxEpochs;
629  }
630  trainOptLog.push_back(trainLog[bestEpoch - 1]);
631  validOptLog.push_back(validLog[bestEpoch - 1]);
632  vector<float> oldWeights = m_GRLNeuro[isector].getWeights();
633  m_GRLNeuro[isector].m_weights = bestWeights;
634  }
635  if (m_saveDebug) {
636  for (unsigned i = nTrain + m_nValid; i < m_trainSets[isector].getNumberOfSamples(); ++i) {
637  float output = m_GRLNeuro.runMLP(isector, m_trainSets[isector].getInput(i));
638  vector<float> target = m_trainSets[isector].getTarget(i);
639  //for (unsigned iout = 0; iout < output.size(); ++iout) {
640  if (((int)target[0]) == 1)h_result_sig[isector]->Fill(output);
641  else h_result_bg[isector]->Fill(output);
642  //}
643  }
644  }
645  // free memory
646  fann_destroy_train(train_data);
647  fann_destroy_train(valid_data);
648  fann_destroy(ann);
649  delete[] nNodes;
650 }
651 
652 void
653 GRLNeuroTrainerModule::saveTraindata(const string& filename, const string& arrayname)
654 {
655  B2INFO("Saving traindata to file " << filename << ", array " << arrayname);
656  TFile datafile(filename.c_str(), "RECREATE");
657  //TObjArray* trainSets = new TObjArray(m_trainSets.size());
658  for (int isector = 0; isector < n_sector; ++isector) {
659  //trainSets->Add(&m_trainSets[isector]);
660  if (m_saveDebug) {
661  h_cdc2d_phi_sig[isector]->Write();
662  h_cdc2d_pt_sig[isector]->Write();
663  h_selTheta_sig[isector]->Write();
664  h_selPhi_sig[isector]->Write();
665  h_selE_sig[isector]->Write();
666  h_result_sig[isector]->Write();
667  h_cdc2d_phi_bg[isector]->Write();
668  h_cdc2d_pt_bg[isector]->Write();
669  h_selTheta_bg[isector]->Write();
670  h_selPhi_bg[isector]->Write();
671  h_selE_bg[isector]->Write();
672  h_result_bg[isector]->Write();
673  }
674  h_ncdcf_sig[0]->Write();
675  h_ncdcs_sig[0]->Write();
676  h_ncdci_sig[0]->Write();
677  h_ncdc_sig[0]->Write();
678  h_necl_sig[0]->Write();
679  h_ncdcf_bg[0]->Write();
680  h_ncdcs_bg[0]->Write();
681  h_ncdci_bg[0]->Write();
682  h_ncdc_bg[0]->Write();
683  h_necl_bg[0]->Write();
684  }
685  //trainSets->Write(arrayname.c_str(), TObject::kSingleKey | TObject::kOverwrite);
686  //datafile.Close();
687  //trainSets->Clear();
688  //delete trainSets;
689  for (int isector = 0; isector < n_sector; ++ isector) {
690  delete h_cdc2d_phi_sig[isector];
691  delete h_cdc2d_pt_sig[isector];
692  delete h_selTheta_sig[isector];
693  delete h_selPhi_sig[isector];
694  delete h_selE_sig[isector];
695  delete h_result_sig[isector];
696  delete h_cdc2d_phi_bg[isector];
697  delete h_cdc2d_pt_bg[isector];
698  delete h_selTheta_bg[isector];
699  delete h_selPhi_bg[isector];
700  delete h_selE_bg[isector];
701  delete h_result_bg[isector];
702  }
703  delete h_ncdcf_sig[0];
704  delete h_ncdcs_sig[0];
705  delete h_ncdci_sig[0];
706  delete h_ncdc_sig[0];
707  delete h_necl_sig[0];
708  delete h_ncdcf_bg[0];
709  delete h_ncdcs_bg[0];
710  delete h_ncdci_bg[0];
711  delete h_ncdc_bg[0];
712  delete h_necl_bg[0];
713  h_cdc2d_phi_sig.clear();
714  h_cdc2d_pt_sig.clear();
715  h_selTheta_sig.clear();
716  h_selPhi_sig.clear();
717  h_selE_sig.clear();
718  h_result_sig.clear();
719  h_cdc2d_phi_bg.clear();
720  h_cdc2d_pt_bg.clear();
721  h_selTheta_bg.clear();
722  h_selPhi_bg.clear();
723  h_selE_bg.clear();
724  h_result_bg.clear();
725  h_ncdcf_sig.clear();
726  h_ncdcs_sig.clear();
727  h_ncdci_sig.clear();
728  h_ncdc_sig.clear();
729  h_necl_sig.clear();
730  h_ncdcf_bg.clear();
731  h_ncdcs_bg.clear();
732  h_ncdci_bg.clear();
733  h_necl_bg.clear();
734 }
735 
736 //bool
737 //GRLNeuroTrainerModule::loadTraindata(const string& filename, const string& arrayname)
738 //{
739 // TFile datafile(filename.c_str(), "READ");
740 // if (!datafile.IsOpen()) {
741 // B2WARNING("Could not open file " << filename);
742 // return false;
743 // }
744 // TObjArray* trainSets = (TObjArray*)datafile.Get(arrayname.c_str());
745 // if (!trainSets) {
746 // datafile.Close();
747 // B2WARNING("File " << filename << " does not contain key " << arrayname);
748 // return false;
749 // }
750 // m_trainSets.clear();
751 // for (int isector = 0; isector < trainSets->GetEntriesFast(); ++isector) {
752 // CDCTriggerMLPData* samples = dynamic_cast<CDCTriggerMLPData*>(trainSets->At(isector));
753 // if (samples) m_trainSets.push_back(*samples);
754 // else B2WARNING("Wrong type " << trainSets->At(isector)->ClassName() << ", ignoring this entry.");
755 // }
756 // trainSets->Clear();
757 // delete trainSets;
758 // datafile.Close();
759 // B2DEBUG(100, "loaded " << m_trainSets.size() << " training sets");
760 // return true;
761 //}
Struct for training data of a single MLP for the neuro trigger.
Definition: GRLMLPData.h:20
const std::vector< float > & getInput(unsigned i) const
get input vector of sample i
Definition: GRLMLPData.h:37
const std::vector< float > & getTarget(unsigned i) const
get target value of sample i
Definition: GRLMLPData.h:39
int m_maxEpochs
Maximal number of training epochs.
GRLNeuroTrainerModule()
Constructor, for setting module description and parameters.
int m_nValid
Number of validation samples.
bool m_load
Switch to load saved parameters from a previous run.
virtual void initialize() override
Initialize the module.
std::string m_TrgECLClusterName
Name of the StoreArray containing the ECL clusters.
int m_checkInterval
Training is stopped if validation error is higher than checkInterval epochs ago, i....
GRLNeuro m_GRLNeuro
Instance of the NeuroTrigger.
virtual void event() override
Called once for each event.
int n_cdc_sector
Number of CDC sectors.
GRLNeuro::Parameters m_parameters
Parameters for the NeuroTrigger.
double m_wMax
Limit for weights.
std::string m_arrayname
Name of the TObjArray holding the networks.
virtual void terminate() override
Do the training for all sectors.
bool m_multiplyNTrain
Switch to multiply number of samples with number of weights.
int m_nThreads
Number of threads for training.
int m_nTest
Number of test samples.
std::string m_GRLCollectionName
Name of the StoreObj containing the input GRL.
std::string m_trainFilename
Name of file where training samples are stored.
void train(unsigned isector)
Train a single MLP.
std::string m_2DfinderCollectionName
Name of the StoreArray containing the input 2D tracks.
int n_ecl_sector
Number of ECL sectors.
std::vector< TH1D * > h_cdc2d_phi_sig
Histograms for monitoring.
double m_nTrainMin
Minimal number of training samples.
std::string m_filename
Name of file where network weights etc.
std::vector< GRLMLPData > m_trainSets
Sets of training data for all sectors.
void saveTraindata(const std::string &filename, const std::string &arrayname="trainSets")
Save all training samples.
std::vector< int > scale_bg
BG scale factor for training.
double m_nTrainMax
Maximal number of training samples.
bool m_saveDebug
If true, save training curve and parameter distribution of training data.
std::string m_trainArrayname
Name of the TObjArray holding the training samples.
int n_sector
Number of Total sectors.
int m_repeatTrain
Number of training runs with different random start weights.
void initialize(const Parameters &p)
Set parameters and get some network independent parameters.
Definition: GRLNeuro.cc:29
float runMLP(unsigned isector, const std::vector< float > &input)
Run an expert MLP.
Definition: GRLNeuro.cc:87
unsigned nSectors() const
return number of neural networks
Definition: GRLNeuro.h:86
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
Class to hold Lorentz transformations from/to CMS and boost vector.
const ROOT::Math::LorentzRotation rotateLabToCms() const
Returns Lorentz transformation from Lab to CMS.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:111
A class of TC Mapping.
Definition: TrgEclMapping.h:26
int getTCThetaIdFromTCId(int)
get [TC Theta ID] from [TC ID]
TVector3 getTCPosition(int)
TC position (cm)
REG_MODULE(arichBtest)
Register the Module.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
double tan(double a)
tan for double
Definition: beamHelpers.h:31
@ c_accept
Accept this event.
Abstract base class for different kinds of events.
std::vector< std::vector< float > > outputScale
Output scale for all networks.
Definition: GRLNeuro.h:58
bool multiplyHidden
If true, multiply nHidden with number of input nodes.
Definition: GRLNeuro.h:56
unsigned nMLP
Number of networks.
Definition: GRLNeuro.h:47
unsigned n_ecl_sector
Number of ECL sectors.
Definition: GRLNeuro.h:64
std::vector< std::vector< float > > nHidden
Number of nodes in each hidden layer for all networks or factor to multiply with number of inputs.
Definition: GRLNeuro.h:52
unsigned n_cdc_sector
Number of CDC sectors.
Definition: GRLNeuro.h:61