Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-09-07 04:37:00

0001 /*
0002  * LutNetworkFixedPointRegression2Outputs.h
0003  *
0004  *  Created on: April 13, 2021
0005  *      Author: Karol Bunkowski, kbunkow@cern.ch
0006  */
0007 
0008 #ifndef L1Trigger_L1TMuonOverlapPhase2_LutNetworkFixedPointRegression2Outputs_h
0009 #define L1Trigger_L1TMuonOverlapPhase2_LutNetworkFixedPointRegression2Outputs_h
0010 
0011 #include "L1Trigger/L1TMuonOverlapPhase2/interface/LutNeuronLayerFixedPoint.h"
0012 
0013 #include "ap_int.h"
0014 
0015 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0016 
0017 #include <cmath>
0018 
0019 #include <boost/property_tree/ptree.hpp>
0020 #include <boost/property_tree/xml_parser.hpp>
0021 
0022 namespace lutNN {
0023 
0024   //_I - number of integer bits in the ap_ufixed, _F - number of fractional bits in the ap_ufixed
0025   //the network has two outputs, and since each output can have different range, the LUTs in the last layer have different I and F
0026   template <int input_I,
0027             int input_F,
0028             std::size_t inputSize,
0029             int layer1_lut_I,
0030             int layer1_lut_F,
0031             int layer1_neurons,
0032             int layer1_output_I,  //to the layer1 output the bias is added to make the layer1 input
0033             int layer2_input_I,
0034             int layer2_lut_I,
0035             int layer2_lut_F,
0036             int layer2_neurons,
0037             int layer3_input_I,
0038             int layer3_0_inputCnt,
0039             int layer3_0_lut_I,
0040             int layer3_0_lut_F,
0041             int output0_I,
0042             int output0_F,
0043             int layer3_1_inputCnt,
0044             int layer3_1_lut_I,
0045             int layer3_1_lut_F,
0046             int output1_I,
0047             int output1_F>
0048   class LutNetworkFixedPointRegression2Outputs : public LutNetworkFixedPointRegressionBase {
0049   public:
0050     LutNetworkFixedPointRegression2Outputs() {
0051       static_assert(layer2_neurons == (layer3_0_inputCnt + layer3_1_inputCnt));
0052 
0053       std::cout << "LutNetworkFixedPoint" << std::endl;
0054       lutLayer1.setName("lutLayer1");
0055       lutLayer2.setName("lutLayer2");
0056       lutLayer3_0.setName("lutLayer3_0");
0057       lutLayer3_1.setName("lutLayer3_1");
0058     };
0059 
0060     ~LutNetworkFixedPointRegression2Outputs() override {}
0061 
0062     typedef LutNeuronLayerFixedPoint<input_I, input_F, inputSize, layer1_lut_I, layer1_lut_F, layer1_neurons, layer1_output_I>
0063         LutLayer1;
0064     LutLayer1 lutLayer1;
0065 
0066     static constexpr unsigned int noHitCntShift = layer1_output_I;  //FIXME should be layer1_output_I ???
0067 
0068     static constexpr int layer2_input_F = layer1_lut_F;
0069 
0070     typedef LutNeuronLayerFixedPoint<layer2_input_I,
0071                                      layer2_input_F,
0072                                      layer1_neurons,
0073                                      layer2_lut_I,
0074                                      layer2_lut_F,
0075                                      layer2_neurons,
0076                                      layer3_input_I>
0077         LutLayer2;
0078     LutLayer2 lutLayer2;
0079 
0080     static constexpr int layer3_input_F = layer2_lut_F;
0081 
0082     typedef LutNeuronLayerFixedPoint<layer3_input_I,
0083                                      layer3_input_F,
0084                                      layer3_0_inputCnt,
0085                                      layer3_0_lut_I,
0086                                      layer3_0_lut_F,
0087                                      1,
0088                                      output0_I>
0089         LutLayer3_0;
0090     LutLayer3_0 lutLayer3_0;  //"lutLayer3_0"
0091 
0092     typedef LutNeuronLayerFixedPoint<layer3_input_I,
0093                                      layer3_input_F,
0094                                      layer3_1_inputCnt,
0095                                      layer3_1_lut_I,
0096                                      layer3_1_lut_F,
0097                                      1,
0098                                      output1_I>
0099         LutLayer3_1;
0100     LutLayer3_1 lutLayer3_1;  //"lutLayer3_1"
0101 
0102     void runWithInterpolation() {
0103       lutLayer1.runWithInterpolation(inputArray);
0104       auto& layer1Out = lutLayer1.getOutWithOffset();
0105 
0106       std::array<ap_ufixed<layer2_input_I + layer2_input_F, layer2_input_I, AP_TRN, AP_SAT>, layer1_neurons>
0107           layer1OutWithBias;
0108       for (unsigned int i = 0; i < layer1Out.size(); i++) {
0109         layer1OutWithBias[i] = layer1Out[i] + layer1Bias;
0110       }
0111 
0112       lutLayer2.runWithInterpolation(layer1OutWithBias);
0113       auto& layer2Out = lutLayer2.getOutWithOffset();
0114 
0115       typename LutLayer3_0::inputArrayType lutLayer3_0_input;
0116       std::copy(layer2Out.begin(), layer2Out.begin() + lutLayer3_0_input.size(), lutLayer3_0_input.begin());
0117 
0118       typename LutLayer3_1::inputArrayType lutLayer3_1_input;
0119       std::copy(layer2Out.begin() + lutLayer3_0_input.size(), layer2Out.end(), lutLayer3_1_input.begin());
0120 
0121       lutLayer3_0.runWithInterpolation(lutLayer3_0_input);
0122       lutLayer3_1.runWithInterpolation(lutLayer3_1_input);
0123     }
0124 
0125     void run(std::vector<float>& inputs, float noHitVal, std::vector<double>& nnResult) override {
0126       unsigned int noHitsCnt = 0;
0127       for (unsigned int iInput = 0; iInput < inputs.size(); iInput++) {
0128         inputArray[iInput] = inputs[iInput];
0129         if (inputs[iInput] == noHitVal)
0130           noHitsCnt++;
0131       }
0132 
0133       unsigned int bias = (noHitsCnt << noHitCntShift);
0134 
0135       //layer1Bias switches the input of the layer2 (i.e. output of the layer1) do different regions in the LUTs
0136       //depending on the  number of layers without hits
0137       layer1Bias = bias;
0138 
0139       runWithInterpolation();
0140 
0141       //output0_I goes to the declaration of the lutLayer3_0, but it does not matter, as it is used only for the outputArray
0142       //auto layer3_0_out = ap_ufixed<output0_I+output0_F, output0_I, AP_RND_CONV, AP_SAT>(lutLayer3_0.getLutOutSum()[0]); //TODO should be AP_RND_CONV rather, but it affect the rate
0143       //auto layer3_1_out = ap_fixed <output1_I+output1_F, output1_I, AP_RND_CONV, AP_SAT>(lutLayer3_1.getLutOutSum()[0]); //here layer3_0_out has size 1
0144       auto layer3_0_out = lutLayer3_0.getLutOutSum()[0];  //here layer3_0_out has size 1
0145       auto layer3_1_out = lutLayer3_1.getLutOutSum()[0];  //here layer3_0_out has size 1
0146 
0147       nnResult[0] = layer3_0_out.to_float();
0148       nnResult[1] = layer3_1_out.to_float();
0149       LogTrace("l1tOmtfEventPrint") << "layer3_0_out[0] " << layer3_0_out[0] << " layer3_1_out[0] " << layer3_1_out[0]
0150                                     << std::endl;
0151     }
0152 
0153     //pt in the hardware scale, ptGeV = (ptHw -1) / 2
0154     int getCalibratedHwPt() override {
0155       auto lutAddr = ap_ufixed<output0_I + output0_F + output0_F, output0_I + output0_F, AP_RND_CONV, AP_SAT>(
0156           lutLayer3_0.getLutOutSum()[0]);
0157       lutAddr = lutAddr << output0_F;
0158       //std::cout<<"lutLayer3_0.getLutOutSum()[0] "<<lutLayer3_0.getLutOutSum()[0]<<" lutAddr.to_uint() "<<lutAddr.to_uint()<<" ptCalibrationArray[lutAddr] "<<ptCalibrationArray[lutAddr.to_uint()]<<std::endl;
0159       return ptCalibrationArray[lutAddr.to_uint()].to_uint();
0160     }
0161 
0162     void save(const std::string& filename) override {
0163       // Create an empty property tree object.
0164       boost::property_tree::ptree tree;
0165 
0166       PUT_VAR(tree, name, output0_I)
0167       PUT_VAR(tree, name, output0_F)
0168       PUT_VAR(tree, name, output1_I)
0169       PUT_VAR(tree, name, output1_F)
0170 
0171       lutLayer1.save(tree, name);
0172       lutLayer2.save(tree, name);
0173       lutLayer3_0.save(tree, name);
0174       lutLayer3_1.save(tree, name);
0175 
0176       int size = ptCalibrationArray.size();
0177       std::string key = "LutNetworkFixedPointRegression2Outputs.ptCalibrationArray";
0178       PUT_VAR(tree, key, size)
0179       std::ostringstream ostr;
0180       for (auto& a : ptCalibrationArray) {
0181         ostr << a.to_uint() << ", ";
0182       }
0183       tree.put(key + ".values", ostr.str());
0184 
0185       boost::property_tree::write_xml(filename,
0186                                       tree,
0187                                       std::locale(),
0188                                       boost::property_tree::xml_parser::xml_writer_make_settings<std::string>(' ', 2));
0189     }
0190 
0191     void load(const std::string& filename) override {
0192       // Create an empty property tree object.
0193       boost::property_tree::ptree tree;
0194 
0195       boost::property_tree::read_xml(filename, tree);
0196 
0197       CHECK_VAR(tree, name, output0_I)
0198       CHECK_VAR(tree, name, output0_F)
0199       CHECK_VAR(tree, name, output1_I)
0200       CHECK_VAR(tree, name, output1_F)
0201 
0202       lutLayer1.load(tree, name);
0203       lutLayer2.load(tree, name);
0204       lutLayer3_0.load(tree, name);
0205       lutLayer3_1.load(tree, name);
0206 
0207       std::string key = "LutNetworkFixedPointRegression2Outputs.ptCalibrationArray";
0208       int size = ptCalibrationArray.size();
0209       CHECK_VAR(tree, key, size)
0210 
0211       auto str = tree.get<std::string>(key + ".values");
0212 
0213       std::stringstream ss(str);
0214       std::string item;
0215 
0216       for (auto& a : ptCalibrationArray) {
0217         if (std::getline(ss, item, ',')) {
0218           a = std::stoul(item, nullptr, 10);
0219         } else {
0220           throw std::runtime_error(
0221               "LutNetworkFixedPointRegression2Outputs::read: number of items get from file is smaller than lut size");
0222         }
0223       }
0224     }
0225 
0226     auto& getPtCalibrationArray() { return ptCalibrationArray; }
0227 
0228   private:
0229     std::array<ap_ufixed<LutLayer1::input_W, input_I, AP_TRN, AP_SAT>, inputSize> inputArray;
0230     ap_uint<layer2_input_I> layer1Bias;
0231 
0232     //ptCalibrationArray size should be 1024, the LSB of the input 0.25 GeV,
0233     //the output is int, with range 0...511, the LSB of output 0.5 GeV
0234     std::array<ap_uint<9>, 1 << (output0_I + output0_F)> ptCalibrationArray;
0235 
0236     std::string name = "LutNetworkFixedPointRegression2Outputs";
0237   };
0238 
0239 } /* namespace lutNN */
0240 
0241 #endif /* L1Trigger_L1TMuonOverlapPhase2_LutNetworkFixedPointRegression2Outputs_h */