BmnRoot 26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Loading...
Searching...
No Matches
BmnGemStripMLPModel.h
Go to the documentation of this file.
1#ifndef BMNGEMSTRIPMLPMODEL_H
2#define BMNGEMSTRIPMLPMODEL_H
3
4// Neural network inference for the GEM strip simulation (no external libraries).
5//
6// BmnGemStripMLPModel - residual MLP trained in Keras (build_generator_mlp):
7//
8// input(input_dim) -> Dense(width) -> LeakyReLU
9// -> [ LayerNorm -> Dense(width) -> LeakyReLU -> Dense(width) -> Add ] x n_blocks
10// -> LayerNorm -> Dense(output_dim) -> sigmoid (or linear)
11//
12// width and n_blocks are read from the model file, so a retrained model with another
13// width / n_blocks does not need recompilation.
14//
15// Model file: binary .bmnmlp written by Converter_KerasToBmnMLP.py
16// (weights, architecture parameters, feature names and test samples for the self-test on loading).
17//
18// Usage:
19// auto model = BmnGemStripMLPModel::GetShared(); // default path, shared between modules
20// auto model = BmnGemStripMLPModel::GetShared("my.bmnmlp"); // explicit path
21// BmnGemStripMLPModel::SetDefaultPath("$VMCWORKDIR/parameters/gem/ANNModels/other.bmnmlp");
22// model->Predict(input, output); // input_dim floats -> output_dim floats
23// std::vector<float> out = model->Predict(input_vector); // the same, empty vector if failed
24//
25// The interface is the same as in BmnGemStripFdeepModel (frugally-deep models).
26//
27// After loading the model is not modified: Predict() can be called from several threads at once.
28
29#include <iostream>
30#include <memory>
31#include <string>
32#include <vector>
33
35{
36
37 public:
38 // Limits (stack buffers in the inference) -----------------------------------
39 static constexpr int kMaxWidth = 1024; // max hidden width
40 static constexpr int kMaxDim = 1024; // max input / output size
41
42 // Output activation of the last Dense layer
48
49 // Constructors -------------------------------------------------------------
51 explicit BmnGemStripMLPModel(const std::string& path, bool verbose = true); // Load(path)
52 //--------------------------------------------------------------------------
53
54 // Destructor
55 virtual ~BmnGemStripMLPModel();
56
57 // Loading ------------------------------------------------------------------
58 // Reads the model file, checks it (format, sizes, checksum) and runs the self-test.
59 // Returns false (and the model stays empty) if anything is wrong; the reason is printed (LOG(error)) if verbose.
60 bool Load(const std::string& path, bool verbose = true);
61 void Clear();
62 bool IsLoaded() const { return fLoaded; }
63 //--------------------------------------------------------------------------
64
65 // Model parameters ---------------------------------------------------------
66 int GetInputDim() const { return fInputDim; }
67 int GetWidth() const { return fWidth; }
68 int GetNBlocks() const { return fNBlocks; }
69 int GetOutputDim() const { return fOutputDim; }
70 int GetOutputActivation() const { return fOutputActivation; }
71 float GetLayerNormEpsilon() const { return fLayerNormEps; }
72 float GetLeakyReLUSlope() const { return fLeakyReLUSlope; }
73 size_t GetNParams() const { return fParams.size(); }
74
75 const std::vector<std::string>& GetFeatureNames() const { return fFeatureNames; }
76 int GetFeatureIndex(const std::string& name) const; // -1 if there is no such feature
77 // true if the feature names are exactly 'expected' (the same order); the reason is written to 'why'
78 bool CheckFeatureNames(const std::vector<std::string>& expected, std::string* why = nullptr) const;
79
80 const std::string& GetFilePath() const { return fFilePath; }
81 const std::string& GetArchHash() const { return fArchHash; }
82 const std::string& GetSourceName() const { return fSourceName; } // name of the original .keras file
83 const std::string& GetCreated() const { return fCreated; } // conversion date
84
85 void Print(std::ostream& os = std::cout) const; // short summary
86 //--------------------------------------------------------------------------
87
88 // Inference ----------------------------------------------------------------
89 // One sample: input[GetInputDim()] -> output[GetOutputDim()]
90 bool Predict(const float* input, float* output) const;
91 // The same with vectors: input.size() must be GetInputDim(); returns an empty vector if failed
92 std::vector<float> Predict(const std::vector<float>& input) const;
93
94 // Several samples with a common first part of the input (the first Dense is computed for it only once):
95 // input of row r = [ common[0 .. n_common-1], specific[r*n_spec .. r*n_spec + n_spec-1] ],
96 // n_spec = GetInputDim() - n_common,
97 // output[r*GetOutputDim() .. ] - output of row r.
98 bool PredictSplit(const float* common, int n_common, const float* specific, int n_rows, float* output) const;
99 //--------------------------------------------------------------------------
100
101 // Self-test: test samples from the model file (Keras outputs) ---------------
102 int GetNTests() const { return fNTests; }
103 float GetTestTolerance() const { return fTestTolerance; }
104 bool RunSelfTest(float* max_abs_diff = nullptr, bool verbose = false) const; // verbose: result by LOG(info)
105 const float* GetTestInput(int itest) const; // nullptr if out of range
106 const float* GetTestOutput(int itest) const; // nullptr if out of range
107 //--------------------------------------------------------------------------
108
109 // Shared models (one copy per file in the process) --------------------------
110 // path: "" - the default path; environment variables ($VMCWORKDIR, ~, ...) are expanded (gSystem->ExpandPathName).
111 // The same file given by different strings is loaded once (the cache key is the expanded path).
112 // A file that failed to load is not reloaded on each call (the warning is printed once);
113 // ClearSharedCache() resets this.
114 static std::shared_ptr<const BmnGemStripMLPModel> GetShared(const std::string& path = "");
115 static void SetDefaultPath(const std::string& path);
116 static std::string GetDefaultPath();
117 static std::string GetBuiltinDefaultPath(); // "$VMCWORKDIR/parameters/gem/ANNModels/GEM_DefaultModel.bmnmlp"
118 static void ClearSharedCache();
119 //--------------------------------------------------------------------------
120
121 private:
122 // h: output of the first Dense (bias included, before the activation) -> output
123 void ForwardFromFirstDense(float* h, float* output) const;
124
125 bool Parse(const std::vector<unsigned char>& buffer, std::string& error);
126
127 private:
129
137
138 std::string fFilePath;
139 std::string fArchHash;
140 std::string fSourceName;
141 std::string fCreated;
142 std::vector<std::string> fFeatureNames;
143
144 // All weights in one array (the order of the file), positions of the parts:
145 std::vector<float> fParams;
146 size_t fOffDenseInW; // [input_dim][width]
147 size_t fOffDenseInB; // [width]
148 size_t fOffBlocks; // n_blocks x { ln_gamma[w], ln_beta[w], W1[w][w], b1[w], W2[w][w], b2[w] }
149 size_t fBlockSize; // floats in one block
150 size_t fOffFinalLnG; // [width]
151 size_t fOffFinalLnB; // [width]
152 size_t fOffDenseOutW; // [width][output_dim]
153 size_t fOffDenseOutB; // [output_dim]
154
155 // Test samples
158 std::vector<float> fTestInputs; // [n_tests][input_dim]
159 std::vector<float> fTestOutputs; // [n_tests][output_dim]
160};
161//------------------------------------------------------------------------------
162
163#endif /* BMNGEMSTRIPMLPMODEL_H */
static std::string GetBuiltinDefaultPath()
const float * GetTestOutput(int itest) const
const float * GetTestInput(int itest) const
bool CheckFeatureNames(const std::vector< std::string > &expected, std::string *why=nullptr) const
const std::string & GetSourceName() const
const std::vector< std::string > & GetFeatureNames() const
bool PredictSplit(const float *common, int n_common, const float *specific, int n_rows, float *output) const
float GetLayerNormEpsilon() const
static std::string GetDefaultPath()
static constexpr int kMaxWidth
bool RunSelfTest(float *max_abs_diff=nullptr, bool verbose=false) const
const std::string & GetArchHash() const
const std::string & GetCreated() const
const std::string & GetFilePath() const
static constexpr int kMaxDim
void ForwardFromFirstDense(float *h, float *output) const
bool Parse(const std::vector< unsigned char > &buffer, std::string &error)
bool Predict(const float *input, float *output) const
float GetLeakyReLUSlope() const
static void SetDefaultPath(const std::string &path)
int GetFeatureIndex(const std::string &name) const
std::vector< float > fTestInputs
std::vector< std::string > fFeatureNames
static std::shared_ptr< const BmnGemStripMLPModel > GetShared(const std::string &path="")
std::vector< float > fTestOutputs
bool Load(const std::string &path, bool verbose=true)
void Print(std::ostream &os=std::cout) const
std::vector< float > fParams