BmnRoot
26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Toggle main menu visibility
Loading...
Searching...
No Matches
BmnGemStripFdeepModel.cxx
Go to the documentation of this file.
1
#include "
BmnGemStripFdeepModel.h
"
2
3
#include "FairLogger.h"
4
#include "
TString.h
"
5
#include "
TSystem.h
"
6
7
#include <algorithm>
8
#include <map>
9
#include <mutex>
10
#include <set>
11
12
// frugally-deep (optional) ------------------------------------------------------
13
// BMN_WITH_FDEEP = 1 : fdeep models can be loaded (fdeep found by include)
14
// BMN_WITH_FDEEP = 0 : built without fdeep, no model can be loaded (the ANN methods use the standard method)
15
// Can be forced from the build: -DBMN_WITH_FDEEP=0 (or =1)
16
#ifndef BMN_WITH_FDEEP
17
#if __has_include("fdeep/fdeep.hpp")
18
#define BMN_WITH_FDEEP 1
19
#else
20
#define BMN_WITH_FDEEP 0
21
#endif
22
#endif
23
24
#if BMN_WITH_FDEEP
25
#define FDEEP_FLOAT_TYPE float
26
#include "fdeep/fdeep.hpp"
27
#endif
28
//------------------------------------------------------------------------------
29
30
namespace
31
{
32
const
char
*
const
kBuiltinDefaultPath =
"$VMCWORKDIR/parameters/gem/ANNModels/GEM_DefaultModel.json"
;
33
34
// Path with environment variables ($VMCWORKDIR, ~, ...) -> real path (ROOT: gSystem->ExpandPathName).
35
// ok = false if it cannot be expanded (an environment variable is not set); the path is returned as given then.
36
std::string ExpandPathName(
const
std::string& path,
bool
* ok =
nullptr
)
37
{
38
TString
expanded(path.c_str());
39
const
bool
failed =
gSystem
->ExpandPathName(expanded);
// kTRUE in case of error
40
if
(ok)
41
*ok = !failed;
42
return
failed ? path : std::string(expanded.
Data
());
43
}
44
45
// Shared models ---------------------------------------------------------------
46
struct
SharedState
47
{
48
std::mutex mutex;
49
std::string default_path = kBuiltinDefaultPath;
50
std::map<std::string, std::shared_ptr<const BmnGemStripFdeepModel>> models;
// key - expanded path
51
std::set<std::string> failed;
// paths that failed to load
52
std::map<std::string, std::string> expanded;
// path as given -> expanded path
53
};
54
55
SharedState& Shared()
56
{
57
static
SharedState state;
58
return
state;
59
}
60
//==============================================================================
61
}
// namespace
62
//------------------------------------------------------------------------------
63
64
// fdeep model and the shape of its input (only here: the header does not need fdeep)
65
struct
BmnGemStripFdeepModel::Impl
66
{
67
#if BMN_WITH_FDEEP
68
Impl
(fdeep::model&&
m
,
const
fdeep::tensor_shape& shape)
69
: model(std::move(
m
))
70
, input_shape(shape)
71
{}
72
fdeep::model model;
73
fdeep::tensor_shape input_shape;
74
#endif
75
};
76
//------------------------------------------------------------------------------
77
78
BmnGemStripFdeepModel::BmnGemStripFdeepModel
()
79
:
fLoaded
(false)
80
,
fInputDim
(0)
81
,
fOutputDim
(0)
82
{}
83
84
BmnGemStripFdeepModel::BmnGemStripFdeepModel
(
const
std::string& path,
bool
verbose)
85
:
BmnGemStripFdeepModel
()
86
{
87
Load
(path, verbose);
88
}
89
90
BmnGemStripFdeepModel::~BmnGemStripFdeepModel
() {}
91
92
void
BmnGemStripFdeepModel::Clear
()
93
{
94
fImpl
.reset();
95
fLoaded
=
false
;
96
fInputDim
= 0;
97
fOutputDim
= 0;
98
fFilePath
.clear();
99
}
100
101
bool
BmnGemStripFdeepModel::IsBuiltWithFdeep
()
102
{
103
return
BMN_WITH_FDEEP
!= 0;
104
}
105
//------------------------------------------------------------------------------
106
107
bool
BmnGemStripFdeepModel::Load
(
const
std::string& path,
bool
verbose)
108
{
109
Clear
();
110
111
bool
expanded_ok =
true
;
112
const
std::string full_path = ExpandPathName(path, &expanded_ok);
113
114
auto
fail = [&](
const
std::string& reason) {
115
if
(verbose)
116
LOG(error) <<
"BmnGemStripFdeepModel: cannot load model "
<< full_path <<
": "
<< reason;
117
Clear
();
118
return
false
;
119
};
120
121
#if BMN_WITH_FDEEP
122
if
(
gSystem
->AccessPathName(full_path.c_str(),
kFileExists
)) {
123
std::string reason =
"file not found"
;
124
if
(!expanded_ok)
125
reason +=
" (an environment variable in the path is not set)"
;
126
return
fail(reason);
127
}
128
129
try
{
130
// verify = false: the test data of the file are not checked (fast loading)
131
fdeep::model model = fdeep::load_model(full_path,
false
, fdeep::dev_null_logger);
132
133
if
(model.get_input_shapes().size() != 1 || model.get_output_shapes().size() != 1)
134
return
fail(
"the model must have one input and one output"
);
135
136
// Sizes of the input and the output: one prediction on zero input
137
const
fdeep::tensors dummy = model.generate_dummy_inputs();
138
const
fdeep::tensors out = model.predict(dummy);
139
if
(dummy.size() != 1 || out.size() != 1)
140
return
fail(
"unexpected number of input / output tensors"
);
141
142
const
fdeep::tensor_shape input_shape = dummy.front().shape();
143
fInputDim
=
static_cast<
int
>
(input_shape.volume());
144
fOutputDim
=
static_cast<
int
>
(out.front().as_vector()->size());
145
fImpl
.reset(
new
Impl
(std::move(model), input_shape));
146
}
catch
(
const
std::exception& e) {
147
return
fail(e.what());
148
}
149
150
fFilePath
= full_path;
151
fLoaded
=
true
;
152
return
true
;
153
#else
154
(void)expanded_ok;
155
return
fail(
"the library is built without frugally-deep"
);
156
#endif
157
}
158
//------------------------------------------------------------------------------
159
160
bool
BmnGemStripFdeepModel::Predict
(
const
float
* input,
float
* output)
const
161
{
162
if
(!
fLoaded
|| !
fImpl
|| !input || !output)
163
return
false
;
164
165
#if BMN_WITH_FDEEP
166
try
{
167
fdeep::tensors in;
168
in.emplace_back(
fImpl
->input_shape, std::vector<float>(input, input +
fInputDim
));
169
const
fdeep::tensors out =
fImpl
->model.predict(in);
170
if
(out.empty())
171
return
false
;
172
const
auto
& result = *out.front().as_vector();
// fdeep vector may use its own allocator
173
if
(
static_cast<
int
>
(result.size()) !=
fOutputDim
)
174
return
false
;
175
std::copy(result.begin(), result.end(), output);
176
return
true
;
177
}
catch
(
const
std::exception& e) {
178
LOG(error) <<
"BmnGemStripFdeepModel: prediction failed ("
<<
fFilePath
<<
"): "
<< e.what();
179
return
false
;
180
}
181
#else
182
return
false
;
183
#endif
184
}
185
186
std::vector<float>
BmnGemStripFdeepModel::Predict
(
const
std::vector<float>& input)
const
187
{
188
if
(!
fLoaded
||
static_cast<
int
>
(input.size()) !=
fInputDim
)
189
return
{};
190
std::vector<float> output(
fOutputDim
);
191
if
(!
Predict
(input.data(), output.data()))
192
return
{};
193
return
output;
194
}
195
//------------------------------------------------------------------------------
196
197
bool
BmnGemStripFdeepModel::PredictSplit
(
const
float
* common,
198
int
n_common,
199
const
float
* specific,
200
int
n_rows,
201
float
* output)
const
202
{
203
if
(!
fLoaded
|| !output || n_rows < 0 || n_common < 0 || n_common >
fInputDim
)
204
return
false
;
205
const
int
n_spec =
fInputDim
- n_common;
206
if
((n_common > 0 && !common) || (n_spec > 0 && n_rows > 0 && !specific))
207
return
false
;
208
209
// Each row separately: [common, specific of the row]
210
std::vector<float> input(
fInputDim
);
211
if
(n_common > 0)
212
std::copy(common, common + n_common, input.begin());
213
for
(
int
r = 0; r < n_rows; ++r) {
214
if
(n_spec > 0)
215
std::copy(specific +
static_cast<
size_t
>
(r) * n_spec, specific +
static_cast<
size_t
>
(r + 1) * n_spec,
216
input.begin() + n_common);
217
if
(!
Predict
(input.data(), output +
static_cast<
size_t
>
(r) *
fOutputDim
))
218
return
false
;
219
}
220
return
true
;
221
}
222
//------------------------------------------------------------------------------
223
224
void
BmnGemStripFdeepModel::Print
(std::ostream& os)
const
225
{
226
if
(!
fLoaded
) {
227
os <<
"BmnGemStripFdeepModel: not loaded"
<< (
IsBuiltWithFdeep
() ?
""
:
" (built without frugally-deep)"
)
228
<<
"\n"
;
229
return
;
230
}
231
os <<
"BmnGemStripFdeepModel: "
<<
fFilePath
<<
"\n"
232
<<
" input "
<<
fInputDim
<<
" -> output "
<<
fOutputDim
<<
"\n"
;
233
}
234
//------------------------------------------------------------------------------
235
236
std::shared_ptr<const BmnGemStripFdeepModel>
BmnGemStripFdeepModel::GetShared
(
const
std::string& path)
237
{
238
SharedState& state = Shared();
239
std::lock_guard<std::mutex> lock(state.mutex);
240
241
// Cache key - the expanded path (the same file given by different strings is loaded once);
242
// the expansion is done once for each path string (GetShared() can be called for each point)
243
const
std::string& given = path.empty() ? state.default_path : path;
244
auto
iexp = state.expanded.find(given);
245
if
(iexp == state.expanded.end())
246
iexp = state.expanded.emplace(given, ExpandPathName(given)).first;
247
const
std::string key = iexp->second;
248
249
auto
it = state.models.find(key);
250
if
(it != state.models.end())
251
return
it->second;
252
if
(state.failed.count(key))
253
return
nullptr
;
254
255
auto
model = std::make_shared<BmnGemStripFdeepModel>();
256
if
(!model->Load(key,
true
)) {
257
LOG(warn) <<
"BmnGemStripFdeepModel: the model "
<< key
258
<<
" is not available (this warning is printed once for the path)"
;
259
state.failed.insert(key);
260
return
nullptr
;
261
}
262
std::shared_ptr<const BmnGemStripFdeepModel> shared = model;
263
state.models[key] = shared;
264
return
shared;
265
}
266
267
void
BmnGemStripFdeepModel::SetDefaultPath
(
const
std::string& path)
268
{
269
SharedState& state = Shared();
270
std::lock_guard<std::mutex> lock(state.mutex);
271
state.default_path = path.empty() ? std::string(kBuiltinDefaultPath) : path;
272
}
273
274
std::string
BmnGemStripFdeepModel::GetDefaultPath
()
275
{
276
SharedState& state = Shared();
277
std::lock_guard<std::mutex> lock(state.mutex);
278
return
state.default_path;
279
}
280
281
std::string
BmnGemStripFdeepModel::GetBuiltinDefaultPath
()
282
{
283
return
kBuiltinDefaultPath;
284
}
285
286
void
BmnGemStripFdeepModel::ClearSharedCache
()
287
{
288
SharedState& state = Shared();
289
std::lock_guard<std::mutex> lock(state.mutex);
290
state.models.clear();
// models in use stay alive while someone holds them
291
state.failed.clear();
292
state.expanded.clear();
293
}
BMN_WITH_FDEEP
#define BMN_WITH_FDEEP
Definition
BmnGemStripFdeepModel.cxx:20
m
__m128 m
Definition
P4_F32vec4.h:27
TString.h
TSystem.h
kFileExists
kFileExists
gSystem
R__EXTERN TSystem * gSystem
BmnGemStripFdeepModel::ClearSharedCache
static void ClearSharedCache()
Definition
BmnGemStripFdeepModel.cxx:286
BmnGemStripFdeepModel::fImpl
std::unique_ptr< Impl > fImpl
Definition
BmnGemStripFdeepModel.h:95
BmnGemStripFdeepModel::GetShared
static std::shared_ptr< const BmnGemStripFdeepModel > GetShared(const std::string &path="")
Definition
BmnGemStripFdeepModel.cxx:236
BmnGemStripFdeepModel::fOutputDim
int fOutputDim
Definition
BmnGemStripFdeepModel.h:99
BmnGemStripFdeepModel::IsBuiltWithFdeep
static bool IsBuiltWithFdeep()
Definition
BmnGemStripFdeepModel.cxx:101
BmnGemStripFdeepModel::BmnGemStripFdeepModel
BmnGemStripFdeepModel()
Definition
BmnGemStripFdeepModel.cxx:78
BmnGemStripFdeepModel::SetDefaultPath
static void SetDefaultPath(const std::string &path)
Definition
BmnGemStripFdeepModel.cxx:267
BmnGemStripFdeepModel::GetBuiltinDefaultPath
static std::string GetBuiltinDefaultPath()
Definition
BmnGemStripFdeepModel.cxx:281
BmnGemStripFdeepModel::~BmnGemStripFdeepModel
virtual ~BmnGemStripFdeepModel()
Definition
BmnGemStripFdeepModel.cxx:90
BmnGemStripFdeepModel::fLoaded
bool fLoaded
Definition
BmnGemStripFdeepModel.h:97
BmnGemStripFdeepModel::Predict
bool Predict(const float *input, float *output) const
Definition
BmnGemStripFdeepModel.cxx:160
BmnGemStripFdeepModel::PredictSplit
bool PredictSplit(const float *common, int n_common, const float *specific, int n_rows, float *output) const
Definition
BmnGemStripFdeepModel.cxx:197
BmnGemStripFdeepModel::Load
bool Load(const std::string &path, bool verbose=true)
Definition
BmnGemStripFdeepModel.cxx:107
BmnGemStripFdeepModel::Print
void Print(std::ostream &os=std::cout) const
Definition
BmnGemStripFdeepModel.cxx:224
BmnGemStripFdeepModel::Clear
void Clear()
Definition
BmnGemStripFdeepModel.cxx:92
BmnGemStripFdeepModel::fFilePath
std::string fFilePath
Definition
BmnGemStripFdeepModel.h:100
BmnGemStripFdeepModel::GetDefaultPath
static std::string GetDefaultPath()
Definition
BmnGemStripFdeepModel.cxx:274
BmnGemStripFdeepModel::fInputDim
int fInputDim
Definition
BmnGemStripFdeepModel.h:98
TString
TString::Data
const char * Data() const
BmnGemStripFdeepModel.h
BmnGemStripFdeepModel::Impl
Definition
BmnGemStripFdeepModel.cxx:66
detectors
gem
BmnGemStripFdeepModel.cxx
Generated on
for BmnRoot by
1.17.0