Skip to content

Commit dbc8f1e

Browse files
committed
Add further reading with pointers to relavant papers in each notebook
1 parent e57213c commit dbc8f1e

8 files changed

Lines changed: 127 additions & 41 deletions

File tree

1_getting_started/1a_train_keras.ipynb

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@
4242
"\n",
4343
"Jets are collimated sprays of particles produced when quarks or gluons are knocked out of colliding protons at the LHC. Identifying the origin of a jet in real time is a core task for LHC trigger systems, which must decide within a few microseconds whether to keep or discard each collision event.\n",
4444
"\n",
45-
"The dataset contains 16 high-level jet substructure observables derived from simulated proton-proton collisions at √s = 13 TeV. These include energy correlation functions, N-subjettiness ratios, a groomed jet mass, and constituent multiplicity. The goal is to classify each jet into one of five categories:\n",
45+
"The dataset contains 16 high-level jet substructure observables derived from simulated proton-proton collisions at \u221as = 13 TeV. These include energy correlation functions, N-subjettiness ratios, a groomed jet mass, and constituent multiplicity. The goal is to classify each jet into one of five categories:\n",
4646
"\n",
4747
"| Label | Jet origin |\n",
4848
"|-------|------------|\n",
4949
"| `g` | Gluon |\n",
5050
"| `q` | Light quark |\n",
51-
"| `w` | W boson decay (W qq') |\n",
52-
"| `z` | Z boson decay (Z qq') |\n",
53-
"| `t` | Top quark decay (t bqq') |"
51+
"| `w` | W boson decay (W \u2192 qq') |\n",
52+
"| `z` | Z boson decay (Z \u2192 qq') |\n",
53+
"| `t` | Top quark decay (t \u2192 bqq') |"
5454
]
5555
},
5656
{
@@ -204,7 +204,7 @@
204204
"cell_type": "markdown",
205205
"metadata": {},
206206
"source": [
207-
"An accuracy of ~75% is expected for this 5-class problem random guessing gives only 20%, and some classes (notably gluon vs. light quark) are physically very similar and genuinely hard to separate even with more sophisticated methods.\n",
207+
"An accuracy of ~75% is expected for this 5-class problem \u2014 random guessing gives only 20%, and some classes (notably gluon vs. light quark) are physically very similar and genuinely hard to separate even with more sophisticated methods.\n",
208208
"\n",
209209
"The ROC (Receiver Operating Characteristic) curve shows, for each class, the trade-off between signal efficiency (true positive rate) and background efficiency (false positive rate) as the decision threshold is varied. The area under the curve (AUC) ranges from 0.5 (random classifier) to 1.0 (perfect). Higher and further to the upper-left is better."
210210
]
@@ -225,6 +225,16 @@
225225
"\n",
226226
"Your model is trained and saved. Open **`1c_hls4ml_synth.ipynb`** to convert it to an FPGA design with hls4ml."
227227
]
228+
},
229+
{
230+
"cell_type": "markdown",
231+
"id": "1c38f1d6",
232+
"metadata": {},
233+
"source": [
234+
"## Further reading\n",
235+
"\n",
236+
"For more details, see: Duarte, Han, Harris et al., \"Fast inference of deep neural networks in FPGAs for particle physics\", JINST 13 P07027 (2018), [arXiv:1804.06913](https://arxiv.org/abs/1804.06913)"
237+
]
228238
}
229239
],
230240
"metadata": {

1_getting_started/1b_train_pytorch.ipynb

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,15 @@
4343
"\n",
4444
"Jets are collimated sprays of particles produced when quarks or gluons are knocked out of colliding protons at the LHC. Identifying the origin of a jet in real time is a core task for LHC trigger systems, which must decide within a few microseconds whether to keep or discard each collision event.\n",
4545
"\n",
46-
"The dataset contains 16 high-level jet substructure observables derived from simulated proton-proton collisions at √s = 13 TeV. These include energy correlation functions, N-subjettiness ratios, a groomed jet mass, and constituent multiplicity. The goal is to classify each jet into one of five categories:\n",
46+
"The dataset contains 16 high-level jet substructure observables derived from simulated proton-proton collisions at \u221as = 13 TeV. These include energy correlation functions, N-subjettiness ratios, a groomed jet mass, and constituent multiplicity. The goal is to classify each jet into one of five categories:\n",
4747
"\n",
4848
"| Label | Jet origin |\n",
4949
"|-------|------------|\n",
5050
"| `g` | Gluon |\n",
5151
"| `q` | Light quark |\n",
52-
"| `w` | W boson decay (W qq') |\n",
53-
"| `z` | Z boson decay (Z qq') |\n",
54-
"| `t` | Top quark decay (t bqq') |"
52+
"| `w` | W boson decay (W \u2192 qq') |\n",
53+
"| `z` | Z boson decay (Z \u2192 qq') |\n",
54+
"| `t` | Top quark decay (t \u2192 bqq') |"
5555
]
5656
},
5757
{
@@ -129,7 +129,7 @@
129129
"outputs": [],
130130
"source": [
131131
"class JetTagger(nn.Module):\n",
132-
" \"\"\"Simple 3-hidden-layer jet tagger: 16 64 32 32 5.\"\"\"\n",
132+
" \"\"\"Simple 3-hidden-layer jet tagger: 16 \u2192 64 \u2192 32 \u2192 32 \u2192 5.\"\"\"\n",
133133
" def __init__(self):\n",
134134
" super().__init__()\n",
135135
" self.fc1 = nn.Linear(16, 64)\n",
@@ -223,7 +223,7 @@
223223
"cell_type": "markdown",
224224
"metadata": {},
225225
"source": [
226-
"An accuracy of ~75% is expected for this 5-class problem random guessing gives only 20%, and some classes (notably gluon vs. light quark) are physically very similar and genuinely hard to separate even with more sophisticated methods.\n",
226+
"An accuracy of ~75% is expected for this 5-class problem \u2014 random guessing gives only 20%, and some classes (notably gluon vs. light quark) are physically very similar and genuinely hard to separate even with more sophisticated methods.\n",
227227
"\n",
228228
"The ROC (Receiver Operating Characteristic) curve shows, for each class, the trade-off between signal efficiency (true positive rate) and background efficiency (false positive rate) as the decision threshold is varied. The area under the curve (AUC) ranges from 0.5 (random classifier) to 1.0 (perfect). Higher and further to the upper-left is better."
229229
]
@@ -244,6 +244,16 @@
244244
"\n",
245245
"Your model is trained and saved. Open **`1c_hls4ml_synth.ipynb`** to convert it to an FPGA design with hls4ml."
246246
]
247+
},
248+
{
249+
"cell_type": "markdown",
250+
"id": "c2603bd5",
251+
"metadata": {},
252+
"source": [
253+
"## Further reading\n",
254+
"\n",
255+
"For more details, see: Duarte, Han, Harris et al., \"Fast inference of deep neural networks in FPGAs for particle physics\", JINST 13 P07027 (2018), [arXiv:1804.06913](https://arxiv.org/abs/1804.06913)"
256+
]
247257
}
248258
],
249259
"metadata": {

2_quantization/2a_qkeras.ipynb

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"source": [
88
"# Part 2a: Quantization with QKeras\n",
99
"\n",
10-
"In this notebook we retrain the jet tagger from Part 1 using **QKeras** (Quantized Keras). With quantization-aware training (QAT), the model is trained with low-precision, fixed-point weights, so the optimizer can correct the effect of quantization during training rather than after enabling lower precisions (and thus resource consumption) without sacrificing accuracy.\n",
10+
"In this notebook we retrain the jet tagger from Part 1 using **QKeras** (Quantized Keras). With quantization-aware training (QAT), the model is trained with low-precision, fixed-point weights, so the optimizer can correct the effect of quantization during training rather than after \u2014 enabling lower precisions (and thus resource consumption) without sacrificing accuracy.\n",
1111
"\n",
1212
"Make sure you have run `1_getting_started/1a_train_keras.ipynb` first, as we load its saved data and use its model as a baseline for comparison."
1313
]
@@ -178,7 +178,7 @@
178178
"The baseline is shown with solid lines, the quantized model with dashed lines.\n",
179179
"\n",
180180
"We should also check that hls4ml can respect the choice to use 6-bits throughout the model and match the accuracy. We'll generate a configuration from this quantized model and plot its performance as the dotted line.\n",
181-
"The generated configuration is printed out. You'll notice that it uses 7 bits for the type, but we specified 6 that's because QKeras doesn't count the sign bit, so the type that actually gets used needs 1 more.\n",
181+
"The generated configuration is printed out. You'll notice that it uses 7 bits for the type, but we specified 6 \u2014 that's because QKeras doesn't count the sign bit, so the type that actually gets used needs 1 more.\n",
182182
"\n",
183183
"We also use the `OutputRoundingSaturationMode` optimizer pass of hls4ml to set the Activation layers to round rather than truncate the cast. This is important for getting good model accuracy at small bit precision. "
184184
]
@@ -294,7 +294,7 @@
294294
"\n",
295295
"For a more accurate picture of resource consumption, you should run **Vivado synthesis** (`vsynth`). This invokes the full Vivado synthesis flow on the generated RTL, producing estimates that are much closer to what you would see after implementation (place-and-route).\n",
296296
"\n",
297-
"**This step can take 10–20 minutes.**"
297+
"**This step can take 10\u201320 minutes.**"
298298
]
299299
},
300300
{
@@ -316,6 +316,19 @@
316316
"source": [
317317
"hls4ml.report.read_vivado_report('../hls4ml_prjs/hls4ml_prj_quantized_part2')"
318318
]
319+
},
320+
{
321+
"cell_type": "markdown",
322+
"id": "14989120",
323+
"metadata": {},
324+
"source": [
325+
"## Further reading\n",
326+
"\n",
327+
"For more details, see:\n",
328+
"\n",
329+
"- Coelho Jr., Kuusela, Zhuang et al., \"Ultra Low-latency, Low-area Inference Accelerators using Heterogeneous Deep Quantization with QKeras and hls4ml\", arXiv (2020), [arXiv:2006.10159](http://arxiv.org/abs/2006.10159)\n",
330+
"- Coelho Jr., Kuusela, Li et al., \"Automatic heterogeneous quantization of deep neural networks for low-latency inference on the edge for particle detectors\", Nature Machine Intelligence (2021), [doi:10.1038/s42256-021-00356-5](https://www.nature.com/articles/s42256-021-00356-5)"
331+
]
319332
}
320333
],
321334
"metadata": {

3_advanced_config/3a_reuse_factor.ipynb

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
"cell_type": "markdown",
8686
"id": "cell-5",
8787
"metadata": {},
88-
"source": "## What is the ReuseFactor?\n\nIn the default (`ReuseFactor = 1`) configuration, hls4ml instantiates one multiplier for every weight in the network. All multiplications for a given layer happen in a single clock cycle, giving the minimum possible latency but using the most multipliers.\n\nSetting `ReuseFactor = N` tells hls4ml to time-multiplex the same multiplier hardware across `N` weight-input pairs. This means the layer takes `N` clock cycles to compute instead of one, but uses roughly `1/N` as many multipliers.\n\n![Reuse factor diagram](../images/part3a_reuse_factor.png)\n\nThe reuse factor must evenly divide the number of weights in each layer. For example, the first layer has `16 × 64 = 1024` weights, so valid reuse factors include 1, 2, 4, 8, 16, 32, 64, etc.\n\nChanging the reuse factor does **not** change the model accuracy the same arithmetic is performed, just spread over more clock cycles. We will verify this below."
88+
"source": "## What is the ReuseFactor?\n\nIn the default (`ReuseFactor = 1`) configuration, hls4ml instantiates one multiplier for every weight in the network. All multiplications for a given layer happen in a single clock cycle, giving the minimum possible latency \u2014 but using the most multipliers.\n\nSetting `ReuseFactor = N` tells hls4ml to time-multiplex the same multiplier hardware across `N` weight-input pairs. This means the layer takes `N` clock cycles to compute instead of one, but uses roughly `1/N` as many multipliers.\n\n![Reuse factor diagram](../images/part3a_reuse_factor.png)\n\nThe reuse factor must evenly divide the number of weights in each layer. For example, the first layer has `16 \u00d7 64 = 1024` weights, so valid reuse factors include 1, 2, 4, 8, 16, 32, 64, etc.\n\nChanging the reuse factor does **not** change the model accuracy \u2014 the same arithmetic is performed, just spread over more clock cycles. We will verify this below."
8989
},
9090
{
9191
"cell_type": "markdown",
@@ -94,7 +94,7 @@
9494
"source": [
9595
"## Set ReuseFactor = 4\n",
9696
"\n",
97-
"Let's create a new configuration with `ReuseFactor = 4` set globally. Note that we use `granularity='model'` here, which applies one set of defaults to all layers equivalent to the config from Part 1c."
97+
"Let's create a new configuration with `ReuseFactor = 4` set globally. Note that we use `granularity='model'` here, which applies one set of defaults to all layers \u2014 equivalent to the config from Part 1c."
9898
]
9999
},
100100
{
@@ -152,7 +152,7 @@
152152
"source": [
153153
"## Compare\n",
154154
"\n",
155-
"Changing the reuse factor only affects resource usage and latency not accuracy. Let's verify that the accuracy and ROC curves are identical."
155+
"Changing the reuse factor only affects resource usage and latency \u2014 not accuracy. Let's verify that the accuracy and ROC curves are identical."
156156
]
157157
},
158158
{
@@ -230,6 +230,16 @@
230230
"print('ReuseFactor = 1 (Part 1c baseline):')\n",
231231
"hls4ml.report.read_vivado_report('../hls4ml_prjs_/hls4ml_prj_base_part1')"
232232
]
233+
},
234+
{
235+
"cell_type": "markdown",
236+
"id": "63bbdc7c",
237+
"metadata": {},
238+
"source": [
239+
"## Further reading\n",
240+
"\n",
241+
"For more details, see: Schulte, Ramhorst, Sun et al., \"hls4ml: A Flexible, Open-Source Platform for Deep Learning Acceleration on Reconfigurable Hardware\", ACM Trans. Reconfigurable Technol. Syst. (2026), [doi:10.1145/3801979](https://dl.acm.org/doi/abs/10.1145/3801979)"
242+
]
233243
}
234244
],
235245
"metadata": {

3_advanced_config/3b_profiling.ipynb

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
"\n",
110110
"With `auto` precision:\n",
111111
"- `weight` and `bias` default to the global model precision (`ap_fixed<16,6>`).\n",
112-
"- `result` and `accum` are computed to be wide enough to hold the worst-case accumulation without overflow these are often much wider than 16 bits. While ensuring no accuracy loss, it may come at the expense of resources.\n",
112+
"- `result` and `accum` are computed to be wide enough to hold the worst-case accumulation without overflow \u2014 these are often much wider than 16 bits. While ensuring no accuracy loss, it may come at the expense of resources.\n",
113113
"\n",
114114
"This configuration is a useful starting point for manual tuning -- you can inspect the profiling plots below to decide which layers can safely use narrower types and accordingly update the config."
115115
]
@@ -141,7 +141,7 @@
141141
"The `hls4ml.model.profiling.numerical` function plots the distribution of weights and biases as a box-and-whisker chart. The **grey boxes** show the range representable with the data types set in the hls4ml config.\n",
142142
"\n",
143143
"The rule of thumb:\n",
144-
"- The grey box should cover the full whisker **to the right** (large values) otherwise weights saturate or wrap around.\n",
144+
"- The grey box should cover the full whisker **to the right** (large values) \u2014 otherwise weights saturate or wrap around.\n",
145145
"- It is acceptable for the box not to reach the left whisker (small values): those weights are simply rounded to zero, which is *often* harmless.\n",
146146
"\n",
147147
"Providing data (here the first 1000 test samples for speed) also shows the same distributions at the **output of each layer**, which reveals whether the activation dynamic range is well-matched to the fixed-point type.\n",
@@ -182,9 +182,9 @@
182182
"source": [
183183
"## Customise precision\n",
184184
"\n",
185-
"After inspecting the profiling plot, let's try narrowing the weight precision of `fc1` from 16 bits to 8 bits (`ap_fixed<8,2>` 8 total bits, 2 integer bits). This reduces the multiplier width and can save significant LUT and DSP resources.\n",
185+
"After inspecting the profiling plot, let's try narrowing the weight precision of `fc1` from 16 bits to 8 bits (`ap_fixed<8,2>` \u2014 8 total bits, 2 integer bits). This reduces the multiplier width and can save significant LUT and DSP resources.\n",
186186
"\n",
187-
"**Note on the output layer:** Using `auto` precision can produce an accumulator at the output of the last fully-connected layer that is wider than the softmax look-up tables can handle. We therefore manually cap it with `fixed<16,6,RND,SAT>`, which also enables rounding and saturation important when narrowing any type that feeds into a non-linear function."
187+
"**Note on the output layer:** Using `auto` precision can produce an accumulator at the output of the last fully-connected layer that is wider than the softmax look-up tables can handle. We therefore manually cap it with `fixed<16,6,RND,SAT>`, which also enables rounding and saturation \u2014 important when narrowing any type that feeds into a non-linear function."
188188
]
189189
},
190190
{
@@ -254,7 +254,7 @@
254254
"source": [
255255
"## Compile, trace, predict\n",
256256
"\n",
257-
"Compile the hls4ml model and call `hls_model.trace` instead of `hls_model.predict`. This returns both the final predictions **and** a dictionary of intermediate layer outputs one array per layer, keyed by layer name.\n",
257+
"Compile the hls4ml model and call `hls_model.trace` instead of `hls_model.predict`. This returns both the final predictions **and** a dictionary of intermediate layer outputs \u2014 one array per layer, keyed by layer name.\n",
258258
"\n",
259259
"We collect the same dictionary from the original model for comparison. We only trace the first 1000 samples since tracing is slower than a plain forward pass."
260260
]
@@ -303,7 +303,7 @@
303303
"source": [
304304
"## Inspect\n",
305305
"\n",
306-
"We can now print, plot, or otherwise compare the output of each layer between the original model and the hls4ml fixed-point emulation. This makes it easy to spot which layer first deviates a sign that the precision there is too narrow.\n",
306+
"We can now print, plot, or otherwise compare the output of each layer between the original model and the hls4ml fixed-point emulation. This makes it easy to spot which layer first deviates \u2014 a sign that the precision there is too narrow.\n",
307307
"\n",
308308
"Let's print the first-layer output for the very first test sample."
309309
]
@@ -353,6 +353,16 @@
353353
"leg = Legend(ax, lines, labels=[MODEL_TYPE, 'hls4ml (8-bit fc1)'], loc='lower right', frameon=False)\n",
354354
"ax.add_artist(leg)"
355355
]
356+
},
357+
{
358+
"cell_type": "markdown",
359+
"id": "6afa959e",
360+
"metadata": {},
361+
"source": [
362+
"## Further reading\n",
363+
"\n",
364+
"For more details, see: Schulte, Ramhorst, Sun et al., \"hls4ml: A Flexible, Open-Source Platform for Deep Learning Acceleration on Reconfigurable Hardware\", ACM Trans. Reconfigurable Technol. Syst. (2026), [doi:10.1145/3801979](https://dl.acm.org/doi/abs/10.1145/3801979)"
365+
]
356366
}
357367
],
358368
"metadata": {

0 commit comments

Comments
 (0)