CMS 3D CMS Logo

HGCalConcentratorAutoEncoderImpl.cc
Go to the documentation of this file.
3 #include <iomanip>
4 
5 // Following example of implementing graphloading from here:
6 // https://gitlab.cern.ch/mrieger/CMSSW-TensorFlowExamples/-/blob/master/GraphLoading/
7 
9  : cellRemap_(conf.getParameter<std::vector<int>>("cellRemap")),
10  cellRemapNoDuplicates_(conf.getParameter<std::vector<int>>("cellRemapNoDuplicates")),
11  encoderShape_(conf.getParameter<std::vector<uint>>("encoderShape")),
12  decoderShape_(conf.getParameter<std::vector<uint>>("decoderShape")),
13  bitsPerInput_(conf.getParameter<int>("nBitsPerInput")),
14  maxBitsPerOutput_(conf.getParameter<int>("maxBitsPerOutput")),
15  outputBitsPerLink_(conf.getParameter<std::vector<int>>("bitsPerLink")),
16  modelFilePaths_(conf.getParameter<std::vector<edm::ParameterSet>>("modelFiles")),
17  linkToGraphMap_(conf.getParameter<std::vector<unsigned int>>("linkToGraphMap")),
18  zeroSuppresionThreshold_(conf.getParameter<double>("zeroSuppresionThreshold")),
19  bitShiftNormalization_(conf.getParameter<bool>("bitShiftNormalization")),
20  saveEncodedValues_(conf.getParameter<bool>("saveEncodedValues")),
21  preserveModuleSum_(conf.getParameter<bool>("preserveModuleSum")) {
22  // find total size of the expected input shape
23  // used for checking the maximum size used in cell Remap
24  nInputs_ = 1;
25  for (const auto& i : encoderShape_) {
26  nInputs_ *= i;
27  }
28 
29  // check the size of the inputs shapes
30  if (encoderShape_.size() != encoderTensorDims_) {
31  throw cms::Exception("BadInitialization")
32  << "Encoder input shapes are currently expected to be " << encoderTensorDims_ << " values";
33  }
34 
35  if (decoderShape_.size() != decoderTensorDims_) {
36  throw cms::Exception("BadInitialization")
37  << "Encoder input shapes are currently expected to be " << decoderTensorDims_ << " values long";
38  }
39 
40  if (cellRemap_.size() != nInputs_) {
41  throw cms::Exception("BadInitialization")
42  << "Size of cellRemap (" << cellRemap_.size()
43  << ") does not agree with the total size specified for the encoder inputs based on the encoderShape variable ("
44  << nInputs_ << ")";
45  }
46 
47  if (cellRemap_.size() != cellRemapNoDuplicates_.size()) {
48  throw cms::Exception("BadInitialization")
49  << "Size of cellRemap (" << cellRemap_.size() << ") does not agree with size of cellRemapNoDuplicates ("
50  << cellRemapNoDuplicates_.size() << ")";
51  }
52 
53  for (unsigned i = 0; i < cellRemap_.size(); i++) {
54  if (cellRemap_[i] > nTriggerCells_ - 1) {
55  throw cms::Exception("BadInitialization")
56  << "cellRemap value " << cellRemap_[i] << " is larger than the number of trigger cells " << nTriggerCells_;
57  }
59  throw cms::Exception("BadInitialization") << "cellRemapNoDuplicates value " << cellRemapNoDuplicates_[i]
60  << " is larger than the number of trigger cells " << nTriggerCells_;
61  }
62  }
63 
64  for (const auto& modelFilePset : modelFilePaths_) {
65  std::string encoderPath = modelFilePset.getParameter<edm::FileInPath>("encoderModelFile").fullPath();
66  std::string decoderPath = modelFilePset.getParameter<edm::FileInPath>("decoderModelFile").fullPath();
67 
68  graphDef_encoder_ = std::unique_ptr<tensorflow::GraphDef>{tensorflow::loadGraphDef(encoderPath)};
69 
70  // create a new session and add the graphDef
71  session_encoder_.push_back(
72  std::unique_ptr<tensorflow::Session>{tensorflow::createSession(graphDef_encoder_.get())});
73 
74  graphDef_decoder_ = std::unique_ptr<tensorflow::GraphDef>{tensorflow::loadGraphDef(decoderPath)};
75 
76  // create a new session and add the graphDef
77  session_decoder_.push_back(
78  std::unique_ptr<tensorflow::Session>{tensorflow::createSession(graphDef_decoder_.get())});
79 
80  //extract encoder tenser names from first graph, check that rest of the names are consistent
81  if (modelFilePset == modelFilePaths_.front()) {
82  inputTensorName_encoder_ = graphDef_encoder_.get()->node(0).name();
83  outputTensorName_encoder_ = graphDef_encoder_.get()->node(graphDef_encoder_.get()->node_size() - 1).name();
84  inputTensorName_decoder_ = graphDef_decoder_.get()->node(0).name();
85  outputTensorName_decoder_ = graphDef_decoder_.get()->node(graphDef_decoder_.get()->node_size() - 1).name();
86  } else {
87  if (inputTensorName_encoder_ != graphDef_encoder_.get()->node(0).name()) {
88  throw cms::Exception("BadInitialization") << "provided list of encoder graphs have different input nodes";
89  }
90  if (outputTensorName_encoder_ != graphDef_encoder_.get()->node(graphDef_encoder_.get()->node_size() - 1).name()) {
91  throw cms::Exception("BadInitialization") << "provided list of encoder graphs have different output nodes";
92  }
93  if (inputTensorName_decoder_ != graphDef_decoder_.get()->node(0).name()) {
94  throw cms::Exception("BadInitialization") << "provided list of decoder graphs have different input nodes";
95  }
96  if (outputTensorName_decoder_ != graphDef_decoder_.get()->node(graphDef_decoder_.get()->node_size() - 1).name()) {
97  throw cms::Exception("BadInitialization") << "provided list of decoder graphs have different output nodes";
98  }
99  }
100  }
101 
102  // check that the appropriate number of links have been specified
103  if (linkToGraphMap_.size() <= maxNumberOfLinks_) {
104  throw cms::Exception("BadInitialization")
105  << "Autoencoder graph number must be specified for all link allocation possibilities. Only "
106  << linkToGraphMap_.size() << " values specified while " << maxNumberOfLinks_ << "links are possible";
107  }
108 
109  // check that all graph indices specified exist in the model file lists
110  for (const auto& graphNumber : linkToGraphMap_) {
111  if (graphNumber >= modelFilePaths_.size()) {
112  throw cms::Exception("BadInitialization")
113  << "Autoencoder graph number " << graphNumber << " is larger than the size of the provided list of graphs "
114  << modelFilePaths_.size();
115  }
116  }
117 }
118 
120  const std::vector<l1t::HGCalTriggerCell>& trigCellVecInput,
121  std::vector<l1t::HGCalTriggerCell>& trigCellVecOutput,
122  std::vector<l1t::HGCalConcentratorData>& ae_encodedLayer_Output) {
123  std::array<double, nTriggerCells_> mipPt;
124  std::array<double, nTriggerCells_> uncompressedCharge;
125  std::array<double, nTriggerCells_> compressedCharge;
126  std::array<double, maxAEInputSize_> ae_inputArray;
127  std::array<double, nTriggerCells_> ae_outputArray;
128 
129  //reset inputs to 0 to account for zero suppressed trigger cells
130  mipPt.fill(0);
131  uncompressedCharge.fill(0);
132  compressedCharge.fill(0);
133  ae_inputArray.fill(0);
134  ae_outputArray.fill(0);
135 
136  double modSum = 0;
137 
138  int bitsPerOutput = outputBitsPerLink_.at(nLinks);
139 
140  // largest expected input and output values, used for bit truncation
141  // values of -1 for the number of bits used to keep full precision, in which case the MaxIntSize variables are not used
142  double inputMaxIntSize = 1;
143  if (bitsPerInput_ > 0)
144  inputMaxIntSize = 1 << bitsPerInput_;
145  double outputMaxIntSize = 1;
146  if (bitsPerOutput > 0)
147  outputMaxIntSize = 1 << bitsPerOutput;
148  double outputMaxIntSizeGlobal = 1;
149  if (maxBitsPerOutput_ > 0)
150  outputMaxIntSizeGlobal = 1 << maxBitsPerOutput_;
151 
152  for (const auto& trigCell : trigCellVecInput) {
153  if (triggerTools_.isScintillator(trigCell.detId()))
154  return; //currently, only silicon modules are setup to work (mapping of scinillators would be different, and needs to be investigated)
155 
156  HGCalTriggerDetId id(trigCell.detId());
157  uint cellu = id.triggerCellU();
158  uint cellv = id.triggerCellV();
159  int inputIndex = cellUVremap_[cellu][cellv];
160  if (inputIndex < 0) {
161  throw cms::Exception("BadInitialization")
162  << "Invalid index provided for trigger cell u=" << cellu << " v=" << cellv << " in cellUVRemap[" << cellu
163  << "][" << cellv << "]";
164  }
165 
166  mipPt[inputIndex] = trigCell.mipPt();
167  uncompressedCharge[inputIndex] = trigCell.uncompressedCharge();
168  compressedCharge[inputIndex] = trigCell.compressedCharge();
169 
170  modSum += trigCell.mipPt();
171  }
172 
173  double normalization = modSum;
174  if (modSum > 0) {
175  //Use a bit shift normalization like will be implemented in ECON, rather than floating point sum
176  //Normalizes to the MSB value of the module sum
178  int msb = int(log2(modSum));
179  normalization = pow(2, msb);
180  }
181 
182  //normalize inputs to module sum
183  for (uint i = 0; i < nInputs_; i++) {
184  int remapIndex = cellRemap_[i];
185  if (remapIndex < 0)
186  continue;
187  ae_inputArray[i] = mipPt[remapIndex] / normalization;
188  //round to precision of input, if bitsPerInput_ is -1 keep full precision
189  if (bitsPerInput_ > 0) {
190  ae_inputArray[i] = std::round(ae_inputArray[i] * inputMaxIntSize) / inputMaxIntSize;
191  }
192  }
193  }
194 
195  tensorflow::Tensor encoder_input(tensorflow::DT_FLOAT,
197 
198  float* d = encoder_input.flat<float>().data();
199  for (uint i = 0; i < nInputs_; i++, d++) {
200  *d = ae_inputArray[i];
201  }
202 
203  int graphIndex = linkToGraphMap_.at(nLinks);
204 
205  std::vector<tensorflow::Tensor> encoder_outputs;
206  tensorflow::run(session_encoder_.at(graphIndex).get(),
207  {{inputTensorName_encoder_, encoder_input}},
209  &encoder_outputs);
210 
211  if (encoder_outputs.empty()) {
212  throw cms::Exception("BadInitialization") << "Autoencoder graph returning empty output vector";
213  }
214 
215  d = encoder_outputs[0].flat<float>().data();
216  for (int i = 0; i < encoder_outputs[0].NumElements(); i++, d++) {
217  ae_encodedLayer_[i] = *d;
218  //truncate the encoded layer bits
219  if (bitsPerOutput > 0 && maxBitsPerOutput_ > 0) {
220  ae_encodedLayer_[i] = std::round(ae_encodedLayer_[i] * outputMaxIntSize) / outputMaxIntSize;
221  }
222  }
223 
224  tensorflow::Tensor decoder_input(tensorflow::DT_FLOAT, {decoderShape_[0], decoderShape_[1]});
225  d = decoder_input.flat<float>().data();
226  for (int i = 0; i < nEncodedLayerNodes_; i++, d++) {
227  *d = ae_encodedLayer_[i];
228  }
229 
230  std::vector<tensorflow::Tensor> decoder_outputs;
231  tensorflow::run(session_decoder_.at(graphIndex).get(),
232  {{inputTensorName_decoder_, decoder_input}},
234  &decoder_outputs);
235 
236  double outputSum = 0.;
237 
238  d = decoder_outputs[0].flat<float>().data();
239  for (uint i = 0; i < nInputs_; i++, d++) {
240  int remapIndex = cellRemapNoDuplicates_[i];
241  if (remapIndex < 0)
242  continue;
243  outputSum += *d * normalization;
244  ae_outputArray[remapIndex] = *d;
245  }
246 
247  double renormalizationFactor = 1.;
248  if (preserveModuleSum_) {
249  renormalizationFactor = modSum / outputSum;
250  }
251 
252  // Add data back into trigger cells
253  if (modSum > 0) {
254  //get detID for everything but cell, take first entry detID and subtract off cellU and cellV contribution
255  HGCalTriggerDetId id(trigCellVecInput.at(0).detId());
256  int subdet = id.subdet();
257  int zp = id.zside();
258  int type = id.type();
259  int layer = id.layer();
260  int waferU = id.waferU();
261  int waferV = id.waferV();
262 
263  //use first TC to find mipPt conversions to Et and ADC
264  float mipPtToEt_conv = trigCellVecInput[0].et() / trigCellVecInput[0].mipPt();
265  float mipToADC_conv = trigCellVecInput[0].hwPt() / (trigCellVecInput[0].mipPt() * cosh(trigCellVecInput[0].eta()));
266 
267  for (int i = 0; i < nTriggerCells_; i++) {
268  if (ae_outputArray[i] > 0) {
269  int cellU = ae_outputCellU_[i];
270  int cellV = ae_outputCellV_[i];
271 
272  HGCalTriggerDetId id(subdet, zp, type, layer, waferU, waferV, cellU, cellV);
273 
275  continue;
276 
278 
279  double mipPt = ae_outputArray[i] * normalization * renormalizationFactor;
280  double adc = mipPt * cosh(point.eta()) * mipToADC_conv;
281  double et = mipPt * mipPtToEt_conv;
282 
283  if (mipPt < zeroSuppresionThreshold_)
284  continue;
285 
286  l1t::HGCalTriggerCell triggerCell(reco::LeafCandidate::LorentzVector(), adc, 0, 0, 0, id);
287  //Keep the pre-autoencoder charge for this cell
288  triggerCell.setUncompressedCharge(uncompressedCharge[i]);
289  triggerCell.setCompressedCharge(compressedCharge[i]);
290  triggerCell.setMipPt(mipPt);
291 
292  math::PtEtaPhiMLorentzVector p4(et, point.eta(), point.phi(), 0.);
293 
294  triggerCell.setP4(p4);
295  triggerCell.setPosition(point);
296 
297  trigCellVecOutput.push_back(triggerCell);
298  }
299  }
300 
301  if (saveEncodedValues_) {
302  id = HGCalTriggerDetId(subdet, zp, type, layer, waferU, waferV, 0, 0);
303  for (int i = 0; i < nEncodedLayerNodes_; i++) {
304  l1t::HGCalConcentratorData encodedLayerData(ae_encodedLayer_[i] * outputMaxIntSizeGlobal, i, id);
305  ae_encodedLayer_Output.push_back(encodedLayerData);
306  }
307  }
308  }
309 }
bool isScintillator(const DetId &id) const
int32_t waferU(const int32_t index)
GraphDef * loadGraphDef(const std::string &pbFile)
Definition: TensorFlow.cc:119
static constexpr int ae_outputCellU_[nTriggerCells_]
const HGCalTriggerGeometryBase * getTriggerGeometry() const
std::vector< std::unique_ptr< tensorflow::Session > > session_decoder_
std::unique_ptr< tensorflow::GraphDef > graphDef_encoder_
std::vector< std::unique_ptr< tensorflow::Session > > session_encoder_
PtEtaPhiMLorentzVectorD PtEtaPhiMLorentzVector
Lorentz vector with cartesian internal representation.
Definition: LorentzVector.h:25
virtual bool validTriggerCell(const unsigned trigger_cell_id) const =0
HGCalConcentratorAutoEncoderImpl(const edm::ParameterSet &conf)
GlobalPoint getTCPosition(const DetId &id) const
static constexpr int cellUVremap_[cellUVSize_][cellUVSize_]
void setMipPt(double value)
void run(Session *session, const NamedTensorList &inputs, const std::vector< std::string > &outputNames, std::vector< Tensor > *outputs, const thread::ThreadPoolOptions &threadPoolOptions)
Definition: TensorFlow.cc:271
void setCompressedCharge(uint32_t value)
d
Definition: ztail.py:151
Session * createSession()
Definition: TensorFlow.cc:136
std::unique_ptr< tensorflow::GraphDef > graphDef_decoder_
void setUncompressedCharge(uint32_t value)
static constexpr unsigned int maxNumberOfLinks_
HLT enums.
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:80
int32_t waferV(const int32_t index)
void select(unsigned nLinks, const std::vector< l1t::HGCalTriggerCell > &trigCellVecInput, std::vector< l1t::HGCalTriggerCell > &trigCellVecOutput, std::vector< l1t::HGCalConcentratorData > &ae_EncodedOutput)
static constexpr int ae_outputCellV_[nTriggerCells_]
void setPosition(const GlobalPoint &position)
void setP4(const LorentzVector &p4) final
set 4-momentum
math::XYZTLorentzVector LorentzVector
Lorentz vector.
Definition: LeafCandidate.h:23
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
std::vector< edm::ParameterSet > modelFilePaths_
*vegas h *****************************************************used in the default bin number in original ***version of VEGAS is ***a higher bin number might help to derive a more precise ***grade subtle point
Definition: invegas.h:5
uint16_t *__restrict__ uint16_t const *__restrict__ adc
std::array< double, nEncodedLayerNodes_ > ae_encodedLayer_