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