Belle II Software development
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
39using namespace Belle2;
40using 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).
44REG_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
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
140void
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 ROOT::Math::XYZVector CellPosition = trgecl_obj->getTCPosition(tc);
209 ROOT::Math::PxPyPzEVector CellLab;
210 CellLab.SetPx(CellPosition.Unit().X());
211 CellLab.SetPy(CellPosition.Unit().Y());
212 CellLab.SetPz(CellPosition.Unit().Z());
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
232void
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
491void
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
518void
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
652void
653GRLNeuroTrainerModule::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]
ROOT::Math::XYZVector getTCPosition(int)
TC position (cm)
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
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
@ c_accept
Accept this event.
Abstract base class for different kinds of events.
STL namespace.
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