ATLAS Offline Software
Toggle main menu visibility
Loading...
Searching...
No Matches
TileCalorimeter
TileRecUtils
src
TileNNEmulator.cxx
Go to the documentation of this file.
1
/*
2
Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3
*/
4
5
#include "
TileNNEmulator.h
"
6
#include <nlohmann/json.hpp>
7
#include <cmath>
8
#include <stdexcept>
9
10
int64_t
TileNNEmulator::rshiftRoundHalfEven
(int64_t v,
int
k) {
11
if
(k <= 0)
return
v;
12
int64_t q = v >> k;
13
int64_t
r
= v - (q << k);
14
int64_t half = int64_t(1) << (k - 1);
15
if
(
r
> half || (
r
== half && (q & 1))) ++q;
16
17
return
q;
18
}
19
20
int64_t
TileNNEmulator::castTo
(int64_t v,
int
fracFrom,
const
FixSpec
& spec) {
21
int
d = fracFrom - spec.frac();
22
if
(d > 0) {
23
v = (spec.round ==
Round::RND_CONV
) ?
rshiftRoundHalfEven
(v, d) : (v >> d);
24
}
else
if
(d < 0) {
25
v <<= -d;
26
}
27
28
int64_t lim = int64_t(1) << (spec.w - 1);
29
switch
(spec.sat) {
30
case
Sat::SAT
:
31
if
(v < -lim) v = -lim;
32
else
if
(v >= lim) v = lim - 1;
33
break
;
34
case
Sat::SAT_SYM
:
35
if
(v <= -lim) v = -lim + 1;
36
else
if
(v >= lim) v = lim - 1;
37
break
;
38
case
Sat::WRAP
:
39
v = ((v + lim) & ((int64_t(1) << spec.w) - 1)) - lim;
40
break
;
41
}
42
43
return
v;
44
}
45
46
float
TileNNEmulator::sValue
(
float
hg,
float
lg)
const
{
47
return
static_cast<
float
>
((hg +
m_lgScale
* lg) /
m_denominator
);
48
}
49
50
int64_t
TileNNEmulator::run
(
const
float
* s)
const
{
51
std::vector<int64_t>
x
(
m_nSamples
);
52
53
for
(
int
k = 0; k <
m_nSamples
; ++k) {
54
// float -> in_t: ldexp scales by 2^frac exactly, llrint rounds the real
55
// value half-to-even (FE_TONEAREST), i.e, AP_RND_CONV.
56
int64_t c = std::llrint(std::ldexp(
static_cast<
double
>
(s[k]),
m_inT
.frac()));
57
c =
castTo
(c,
m_inT
.frac(),
m_inT
);
58
x
[k] =
castTo
(c,
m_inT
.frac(),
m_castT
);
59
}
60
61
int
frac =
m_castT
.frac();
62
std::vector<int64_t>
y
;
63
64
for
(
const
Layer
& l :
m_layers
) {
65
if
(l.op ==
Op::Dense
) {
66
y
.assign(l.nOut, 0);
67
68
for
(
int
i = 0; i < l.nIn; ++i) {
69
for
(
int
j = 0; j < l.nOut; ++j) {
70
int64_t p =
x
[i] * l.w[i * l.nOut + j];
71
y
[j] +=
castTo
(p, frac + l.weightT.frac(), l.accumT);
72
}
73
}
74
75
int
up = l.biasT.frac() - l.accumT.frac();
76
77
for
(
int
j = 0; j < l.nOut; ++j) {
78
y
[j] =
castTo
((
y
[j] << up) + l.b[j], l.biasT.frac(), l.outT);
79
}
80
}
else
{
81
y
.resize(l.nOut);
82
83
for
(
int
j = 0; j < l.nOut; ++j) {
84
// Negative branch: multiplying by alpha = 2^-alphaShift is a
85
// reinterpretation of the code at alphaShift more fractional bits.
86
int
from = (
x
[j] > 0) ? frac : frac + l.alphaShift;
87
y
[j] =
castTo
(
x
[j], from, l.outT);
88
}
89
}
90
91
frac = l.outT.frac();
92
x
.swap(
y
);
93
}
94
95
return
x
[0];
96
}
97
98
bool
TileNNEmulator::load
(
const
std::string& jsonText, std::string&
error
) {
99
using
nlohmann::json;
100
101
auto
fix = [](
const
json
& j) {
102
FixSpec
t;
103
t.w = j.at(
"w"
).get<
int
>();
104
t.i = j.at(
"i"
).get<
int
>();
105
std::string
r
= j.at(
"round"
).get<std::string>();
106
std::string s = j.at(
"sat"
).get<std::string>();
107
if
(
r
==
"RND_CONV"
) t.round =
Round::RND_CONV
;
108
else
if
(
r
==
"TRN"
) t.round =
Round::TRN
;
109
else
throw
std::runtime_error(
"unknown rounding mode '"
+
r
+
"'"
);
110
if
(s ==
"SAT"
) t.sat =
Sat::SAT
;
111
else
if
(s ==
"SAT_SYM"
) t.sat =
Sat::SAT_SYM
;
112
else
if
(s ==
"WRAP"
) t.sat =
Sat::WRAP
;
113
else
throw
std::runtime_error(
"unknown saturation mode '"
+ s +
"'"
);
114
115
return
t;
116
};
117
118
try
{
119
json
cfg = json::parse(jsonText);
120
if
(cfg.at(
"format_version"
).get<
int
>() != 1) {
121
throw
std::runtime_error(
"unsupported format_version"
);
122
}
123
124
const
json
& in = cfg.at(
"input"
);
125
m_nSamples
= in.at(
"n_samples"
).get<
int
>();
126
m_lgScale
= in.at(
"lg_scale"
).get<
double
>();
127
m_denominator
= in.at(
"denominator"
).get<
double
>();
128
m_inT
= fix(in.at(
"in_t"
));
129
m_castT
= fix(in.at(
"cast_t"
));
130
m_ampScale
= cfg.at(
"output"
).at(
"amplitude_scale"
).get<
double
>();
131
m_layers
.clear();
132
int
width
=
m_nSamples
;
133
134
for
(
const
json
& jl : cfg.at(
"layers"
)) {
135
Layer
l;
136
std::string op = jl.at(
"op"
).get<std::string>();
137
if
(op ==
"dense"
) {
138
l.op =
Op::Dense
;
139
l.nIn = jl.at(
"n_in"
).get<
int
>();
140
l.nOut = jl.at(
"n_out"
).get<
int
>();
141
l.weightT = fix(jl.at(
"weight_t"
));
142
l.accumT = fix(jl.at(
"accum_t"
));
143
l.biasT = fix(jl.at(
"bias_t"
));
144
l.outT = fix(jl.at(
"out_t"
));
145
l.w = jl.at(
"weights"
).get<std::vector<int64_t>>();
146
l.b = jl.at(
"bias"
).get<std::vector<int64_t>>();
147
if
(l.w.size() !=
size_t
(l.nIn) * l.nOut || l.b.size() !=
size_t
(l.nOut)) {
148
throw
std::runtime_error(
"dense layer weight/bias size mismatch"
);
149
}
150
151
if
(l.biasT.frac() < l.accumT.frac()) {
152
throw
std::runtime_error(
"bias grid coarser than accumulator grid"
);
153
}
154
}
else
if
(op ==
"leaky_relu"
) {
155
l.op =
Op::LeakyRelu
;
156
l.nIn = l.nOut = jl.at(
"n"
).get<
int
>();
157
l.alphaShift = jl.at(
"alpha_shift"
).get<
int
>();
158
l.outT = fix(jl.at(
"out_t"
));
159
}
else
{
160
throw
std::runtime_error(
"unknown op '"
+ op +
"'"
);
161
}
162
163
if
(l.nIn !=
width
) {
164
throw
std::runtime_error(
"layer input width "
+ std::to_string(l.nIn)
165
+
" does not chain from "
+ std::to_string(
width
));
166
}
167
168
width
= l.nOut;
169
m_layers
.push_back(std::move(l));
170
}
171
172
if
(
m_layers
.empty() ||
width
!= 1) {
173
throw
std::runtime_error(
"network must end in a single output"
);
174
}
175
}
catch
(
const
std::exception& e) {
176
error
= e.what();
177
m_layers
.clear();
178
179
return
false
;
180
}
181
182
return
true
;
183
}
json
nlohmann::json json
Definition
HistogramDef.cxx:9
width
const double width
Definition
TTileTripReader.cxx:24
TileNNEmulator.h
y
#define y
x
#define x
TileNNEmulator::m_lgScale
double m_lgScale
Definition
TileNNEmulator.h:67
TileNNEmulator::m_castT
FixSpec m_castT
Definition
TileNNEmulator.h:70
TileNNEmulator::m_denominator
double m_denominator
Definition
TileNNEmulator.h:68
TileNNEmulator::castTo
static int64_t castTo(int64_t v, int fracFrom, const FixSpec &spec)
Definition
TileNNEmulator.cxx:20
TileNNEmulator::sValue
float sValue(float hg, float lg) const
Combined dual-gain input sample S = (hg + lgScale*lg) / denominator.
Definition
TileNNEmulator.cxx:46
TileNNEmulator::m_nSamples
int m_nSamples
Definition
TileNNEmulator.h:66
TileNNEmulator::rshiftRoundHalfEven
static int64_t rshiftRoundHalfEven(int64_t v, int k)
Definition
TileNNEmulator.cxx:10
TileNNEmulator::m_layers
std::vector< Layer > m_layers
Definition
TileNNEmulator.h:71
TileNNEmulator::Round::TRN
@ TRN
Definition
TileNNEmulator.h:42
TileNNEmulator::Round::RND_CONV
@ RND_CONV
Definition
TileNNEmulator.h:42
TileNNEmulator::run
int64_t run(const float *s) const
Definition
TileNNEmulator.cxx:50
TileNNEmulator::m_ampScale
double m_ampScale
Definition
TileNNEmulator.h:69
TileNNEmulator::Sat::SAT_SYM
@ SAT_SYM
Definition
TileNNEmulator.h:43
TileNNEmulator::Sat::SAT
@ SAT
Definition
TileNNEmulator.h:43
TileNNEmulator::Sat::WRAP
@ WRAP
Definition
TileNNEmulator.h:43
TileNNEmulator::m_inT
FixSpec m_inT
Definition
TileNNEmulator.h:70
TileNNEmulator::Op::Dense
@ Dense
Definition
TileNNEmulator.h:53
TileNNEmulator::Op::LeakyRelu
@ LeakyRelu
Definition
TileNNEmulator.h:53
TileNNEmulator::load
bool load(const std::string &jsonText, std::string &error)
Definition
TileNNEmulator.cxx:98
r
int r
Definition
globals.cxx:22
error
Definition
IImpactPoint3dEstimator.h:72
TileNNEmulator::FixSpec
Definition
TileNNEmulator.h:45
TileNNEmulator::Layer
Definition
TileNNEmulator.h:55
Generated on
for ATLAS Offline Software by
1.17.0