ATLAS Offline Software
Loading...
Searching...
No Matches
TileNNEmulator Class Reference

Bit-exact software emulator of the TilePPr neural-network energy reconstruction. More...

#include <TileNNEmulator.h>

Collaboration diagram for TileNNEmulator:

Classes

struct  FixSpec
struct  Layer

Public Member Functions

bool load (const std::string &jsonText, std::string &error)
int nSamples () const
float sValue (float hg, float lg) const
 Combined dual-gain input sample S = (hg + lgScale*lg) / denominator.
int64_t run (const float *s) const
int outFracBits () const
 Fractional bits of the output word (code * 2^-outFracBits() = value).
double amplitudeScale () const

Private Types

enum class  Round { RND_CONV , TRN }
enum class  Sat { SAT , SAT_SYM , WRAP }
enum class  Op { Dense , LeakyRelu }

Static Private Member Functions

static int64_t rshiftRoundHalfEven (int64_t v, int k)
static int64_t castTo (int64_t v, int fracFrom, const FixSpec &spec)

Private Attributes

int m_nSamples = 0
double m_lgScale = 0.0
double m_denominator = 0.0
double m_ampScale = 0.0
FixSpec m_inT
FixSpec m_castT
std::vector< Layerm_layers

Detailed Description

Bit-exact software emulator of the TilePPr neural-network energy reconstruction.

Definition at line 15 of file TileNNEmulator.h.

Member Enumeration Documentation

◆ Op

enum class TileNNEmulator::Op
strongprivate
Enumerator
Dense 
LeakyRelu 

Definition at line 53 of file TileNNEmulator.h.

53{ Dense, LeakyRelu };

◆ Round

enum class TileNNEmulator::Round
strongprivate
Enumerator
RND_CONV 
TRN 

Definition at line 42 of file TileNNEmulator.h.

42{ RND_CONV, TRN };

◆ Sat

enum class TileNNEmulator::Sat
strongprivate
Enumerator
SAT 
SAT_SYM 
WRAP 

Definition at line 43 of file TileNNEmulator.h.

43{ SAT, SAT_SYM, WRAP };

Member Function Documentation

◆ amplitudeScale()

double TileNNEmulator::amplitudeScale ( ) const
inline

Definition at line 39 of file TileNNEmulator.h.

39{ return m_ampScale; }

◆ castTo()

int64_t TileNNEmulator::castTo ( int64_t v,
int fracFrom,
const FixSpec & spec )
staticprivate

Definition at line 20 of file TileNNEmulator.cxx.

20 {
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}
static int64_t rshiftRoundHalfEven(int64_t v, int k)

◆ load()

bool TileNNEmulator::load ( const std::string & jsonText,
std::string & error )
Parameters
jsonTextthe JSON document itself (not a file name, so the payload can later come from the conditions database)
errorfilled with a diagnostic on failure
Returns
true on success, on any problem (malformed JSON, unknown op, size or type inconsistency) returns false and leaves the emulator unusable

Definition at line 98 of file TileNNEmulator.cxx.

98 {
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}
nlohmann::json json
const double width
std::vector< Layer > m_layers
int r
Definition globals.cxx:22
l
Printing final latex table to .tex output file.
float j(const xAOD::IParticle &, const xAOD::TrackMeasurementValidation &hit, const Eigen::Matrix3d &jab_inv)

◆ nSamples()

int TileNNEmulator::nSamples ( ) const
inline

Definition at line 27 of file TileNNEmulator.h.

27{ return m_nSamples; }

◆ outFracBits()

int TileNNEmulator::outFracBits ( ) const
inline

Fractional bits of the output word (code * 2^-outFracBits() = value).

Definition at line 38 of file TileNNEmulator.h.

38{ return m_layers.back().outT.frac(); }

◆ rshiftRoundHalfEven()

int64_t TileNNEmulator::rshiftRoundHalfEven ( int64_t v,
int k )
staticprivate

Definition at line 10 of file TileNNEmulator.cxx.

10 {
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}

◆ run()

int64_t TileNNEmulator::run ( const float * s) const
Returns
the raw integer code of the output fixed-point word

Definition at line 50 of file TileNNEmulator.cxx.

50 {
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}
#define y
#define x
static int64_t castTo(int64_t v, int fracFrom, const FixSpec &spec)

◆ sValue()

float TileNNEmulator::sValue ( float hg,
float lg ) const

Combined dual-gain input sample S = (hg + lgScale*lg) / denominator.

Definition at line 46 of file TileNNEmulator.cxx.

46 {
47 return static_cast<float>((hg + m_lgScale * lg) / m_denominator);
48}

Member Data Documentation

◆ m_ampScale

double TileNNEmulator::m_ampScale = 0.0
private

Definition at line 69 of file TileNNEmulator.h.

◆ m_castT

FixSpec TileNNEmulator::m_castT
private

Definition at line 70 of file TileNNEmulator.h.

◆ m_denominator

double TileNNEmulator::m_denominator = 0.0
private

Definition at line 68 of file TileNNEmulator.h.

◆ m_inT

FixSpec TileNNEmulator::m_inT
private

Definition at line 70 of file TileNNEmulator.h.

◆ m_layers

std::vector<Layer> TileNNEmulator::m_layers
private

Definition at line 71 of file TileNNEmulator.h.

◆ m_lgScale

double TileNNEmulator::m_lgScale = 0.0
private

Definition at line 67 of file TileNNEmulator.h.

◆ m_nSamples

int TileNNEmulator::m_nSamples = 0
private

Definition at line 66 of file TileNNEmulator.h.


The documentation for this class was generated from the following files: