sparsepixels 0.3.0__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sparsepixels-0.3.0/sparsepixels.egg-info → sparsepixels-0.3.1}/PKG-INFO +38 -21
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/README.md +37 -20
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/setup.cfg +1 -1
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/sparsepixels/utils.py +13 -5
- {sparsepixels-0.3.0 → sparsepixels-0.3.1/sparsepixels.egg-info}/PKG-INFO +38 -21
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/LICENSE +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/notebook/utils.py +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/pyproject.toml +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/setup.py +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/sparsepixels/__init__.py +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/sparsepixels/img/logo.png +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/sparsepixels/layers.py +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/sparsepixels.egg-info/SOURCES.txt +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/sparsepixels.egg-info/dependency_links.txt +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/sparsepixels.egg-info/requires.txt +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/sparsepixels.egg-info/top_level.txt +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/tests/__init__.py +0 -0
- {sparsepixels-0.3.0 → sparsepixels-0.3.1}/tests/test_model.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sparsepixels
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Efficient convolution for sparse data on FPGAs
|
|
5
5
|
Home-page: https://github.com/hftsoi/sparse-pixels
|
|
6
6
|
Author: Ho Fung Tsoi
|
|
@@ -47,20 +47,16 @@ pip install sparsepixels
|
|
|
47
47
|
|
|
48
48
|
## Getting Started
|
|
49
49
|
|
|
50
|
-
Import the sparse layers, the quantization library (HGQ2), and the training utilities:
|
|
51
|
-
|
|
52
50
|
```python
|
|
53
51
|
import keras
|
|
54
52
|
from keras.layers import Flatten, Activation
|
|
55
|
-
from hgq.layers import
|
|
53
|
+
from hgq.layers import QDense
|
|
56
54
|
from hgq.config import QuantizerConfigScope, LayerConfigScope
|
|
57
55
|
from hgq.quantizer.config import QuantizerConfig
|
|
58
56
|
from sparsepixels.layers import InputReduce, QConv2DSparse, AveragePooling2DSparse, MaxPooling2DSparse
|
|
59
57
|
from sparsepixels.utils import (
|
|
60
|
-
active_pixels_vs_threshold, plot_reduced_examples,
|
|
61
|
-
|
|
62
|
-
SparseTrainingMonitor, plot_history,
|
|
63
|
-
print_quantization, plot_quantization,
|
|
58
|
+
active_pixels_vs_threshold, plot_reduced_examples, cosine_lr,
|
|
59
|
+
SparseTrainingMonitor, plot_history, print_quantization, plot_quantization,
|
|
64
60
|
)
|
|
65
61
|
```
|
|
66
62
|
|
|
@@ -112,31 +108,34 @@ with (
|
|
|
112
108
|
model = keras.Model(x_in, x)
|
|
113
109
|
```
|
|
114
110
|
|
|
115
|
-
Train the model
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
`layer.threshold`.
|
|
111
|
+
Train the model with `SparseTrainingMonitor`. It records the loss breakdown, the learned
|
|
112
|
+
budget/threshold and the EBOPS each epoch, and it corrects the EBOPS (a proxy for the quantized
|
|
113
|
+
hardware cost) to the sparse compute automatically, so no extra setup is needed. The
|
|
114
|
+
only sparse-specific choices are the cosine-decayed learning rate and `restore_best_weights`, which
|
|
115
|
+
keep the learned budget from over-compressing near the end of training.
|
|
121
116
|
|
|
122
117
|
```python
|
|
123
|
-
set_sparse_ebops_factor(model)
|
|
124
|
-
|
|
125
|
-
steps_per_epoch = len(x_train) // 128
|
|
126
118
|
early_stop = keras.callbacks.EarlyStopping(monitor='val_accuracy', mode='max', patience=20, restore_best_weights=True)
|
|
127
119
|
model.compile(
|
|
128
|
-
optimizer=keras.optimizers.Adam(cosine_lr(1e-3, epochs=100, steps_per_epoch=
|
|
120
|
+
optimizer=keras.optimizers.Adam(cosine_lr(1e-3, epochs=100, steps_per_epoch=len(x_train) // 128)),
|
|
129
121
|
loss='categorical_crossentropy', metrics=['accuracy'],
|
|
130
122
|
)
|
|
131
123
|
history = model.fit(x_train, y_train, validation_data=(x_val, y_val),
|
|
132
124
|
epochs=100, batch_size=128, callbacks=[early_stop, SparseTrainingMonitor()])
|
|
125
|
+
```
|
|
133
126
|
|
|
127
|
+
After training, plot the diagnostics and read out the learned sparsity to deploy. `plot_history`
|
|
128
|
+
shows the loss breakdown, the learned budget/threshold and the EBOPS in one figure.
|
|
129
|
+
`print_quantization` / `plot_quantization` summarize the per-layer bit-widths. The values to
|
|
130
|
+
deploy are `layer.n_max_pixels` and `layer.threshold` (hls4ml converter will auto-parse these from the model).
|
|
131
|
+
|
|
132
|
+
```python
|
|
134
133
|
plot_history(history, early_stopping=early_stop) # loss breakdown, budget, threshold, EBOPS
|
|
135
134
|
print_quantization(model) # per-layer bit-width distribution and EBOPS
|
|
136
135
|
plot_quantization(model)
|
|
137
136
|
|
|
138
137
|
ir = model.get_layer('input_reduce')
|
|
139
|
-
print(f"
|
|
138
|
+
print(f"n_max_pixels={ir.n_max_pixels}, threshold={ir.threshold:.3f}")
|
|
140
139
|
```
|
|
141
140
|
|
|
142
141
|
## Converting a trained model to HLS with hls4ml
|
|
@@ -147,13 +146,31 @@ print(f"deploy with n_max_pixels={ir.n_max_pixels}, threshold={ir.threshold:.3f}
|
|
|
147
146
|
> pip install "git+https://github.com/hftsoi/hls4ml.git@sparsepixels"
|
|
148
147
|
> ```
|
|
149
148
|
|
|
150
|
-
Once installed,
|
|
149
|
+
Once installed, pull a config from the trained model, optionally set the per-layer parallelization
|
|
150
|
+
knobs, and convert:
|
|
151
151
|
|
|
152
152
|
```python
|
|
153
153
|
import hls4ml
|
|
154
154
|
|
|
155
155
|
hls_config = hls4ml.utils.config_from_keras_model(model, granularity='name')
|
|
156
|
-
hls_config.setdefault('Model', {})['PipelineStyle'] = 'dataflow' #
|
|
156
|
+
hls_config.setdefault('Model', {})['PipelineStyle'] = 'dataflow' # "#pragma HLS DATAFLOW"
|
|
157
|
+
|
|
158
|
+
# Optional per-layer parallelization knobs. Omit them for the fully-parallel, lowest-latency default.
|
|
159
|
+
# input_reduce Variant : 'tree' (default, lowest latency) or 'stream' (fewer resources)
|
|
160
|
+
# conv* PixelParallelFactor : active pixels in parallel (<= n_max_pixels)
|
|
161
|
+
# FiltParallelFactor : filters in parallel (<= that conv's filters)
|
|
162
|
+
# pool* PixelParallelFactor : active pixels in parallel
|
|
163
|
+
# ChanParallelFactor : channels in parallel
|
|
164
|
+
# flatten ParallelFactor : scatter positions in parallel (<= out_height * out_width)
|
|
165
|
+
n_sparse = model.get_layer('input_reduce').n_max_pixels
|
|
166
|
+
knobs = {
|
|
167
|
+
'input_reduce': {'Variant': 'stream'},
|
|
168
|
+
'conv1': {'PixelParallelFactor': n_sparse, 'FiltParallelFactor': 3},
|
|
169
|
+
'pool1': {'PixelParallelFactor': n_sparse, 'ChanParallelFactor': 3},
|
|
170
|
+
'flatten': {'ParallelFactor': 14 * 14}, # this model pools 28*28 -> 14*14
|
|
171
|
+
}
|
|
172
|
+
for name, cfg in knobs.items():
|
|
173
|
+
hls_config['LayerName'].setdefault(name, {}).update(cfg)
|
|
157
174
|
|
|
158
175
|
hls_model = hls4ml.converters.convert_from_keras_model(
|
|
159
176
|
model,
|
|
@@ -28,20 +28,16 @@ pip install sparsepixels
|
|
|
28
28
|
|
|
29
29
|
## Getting Started
|
|
30
30
|
|
|
31
|
-
Import the sparse layers, the quantization library (HGQ2), and the training utilities:
|
|
32
|
-
|
|
33
31
|
```python
|
|
34
32
|
import keras
|
|
35
33
|
from keras.layers import Flatten, Activation
|
|
36
|
-
from hgq.layers import
|
|
34
|
+
from hgq.layers import QDense
|
|
37
35
|
from hgq.config import QuantizerConfigScope, LayerConfigScope
|
|
38
36
|
from hgq.quantizer.config import QuantizerConfig
|
|
39
37
|
from sparsepixels.layers import InputReduce, QConv2DSparse, AveragePooling2DSparse, MaxPooling2DSparse
|
|
40
38
|
from sparsepixels.utils import (
|
|
41
|
-
active_pixels_vs_threshold, plot_reduced_examples,
|
|
42
|
-
|
|
43
|
-
SparseTrainingMonitor, plot_history,
|
|
44
|
-
print_quantization, plot_quantization,
|
|
39
|
+
active_pixels_vs_threshold, plot_reduced_examples, cosine_lr,
|
|
40
|
+
SparseTrainingMonitor, plot_history, print_quantization, plot_quantization,
|
|
45
41
|
)
|
|
46
42
|
```
|
|
47
43
|
|
|
@@ -93,31 +89,34 @@ with (
|
|
|
93
89
|
model = keras.Model(x_in, x)
|
|
94
90
|
```
|
|
95
91
|
|
|
96
|
-
Train the model
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
`layer.threshold`.
|
|
92
|
+
Train the model with `SparseTrainingMonitor`. It records the loss breakdown, the learned
|
|
93
|
+
budget/threshold and the EBOPS each epoch, and it corrects the EBOPS (a proxy for the quantized
|
|
94
|
+
hardware cost) to the sparse compute automatically, so no extra setup is needed. The
|
|
95
|
+
only sparse-specific choices are the cosine-decayed learning rate and `restore_best_weights`, which
|
|
96
|
+
keep the learned budget from over-compressing near the end of training.
|
|
102
97
|
|
|
103
98
|
```python
|
|
104
|
-
set_sparse_ebops_factor(model)
|
|
105
|
-
|
|
106
|
-
steps_per_epoch = len(x_train) // 128
|
|
107
99
|
early_stop = keras.callbacks.EarlyStopping(monitor='val_accuracy', mode='max', patience=20, restore_best_weights=True)
|
|
108
100
|
model.compile(
|
|
109
|
-
optimizer=keras.optimizers.Adam(cosine_lr(1e-3, epochs=100, steps_per_epoch=
|
|
101
|
+
optimizer=keras.optimizers.Adam(cosine_lr(1e-3, epochs=100, steps_per_epoch=len(x_train) // 128)),
|
|
110
102
|
loss='categorical_crossentropy', metrics=['accuracy'],
|
|
111
103
|
)
|
|
112
104
|
history = model.fit(x_train, y_train, validation_data=(x_val, y_val),
|
|
113
105
|
epochs=100, batch_size=128, callbacks=[early_stop, SparseTrainingMonitor()])
|
|
106
|
+
```
|
|
114
107
|
|
|
108
|
+
After training, plot the diagnostics and read out the learned sparsity to deploy. `plot_history`
|
|
109
|
+
shows the loss breakdown, the learned budget/threshold and the EBOPS in one figure.
|
|
110
|
+
`print_quantization` / `plot_quantization` summarize the per-layer bit-widths. The values to
|
|
111
|
+
deploy are `layer.n_max_pixels` and `layer.threshold` (hls4ml converter will auto-parse these from the model).
|
|
112
|
+
|
|
113
|
+
```python
|
|
115
114
|
plot_history(history, early_stopping=early_stop) # loss breakdown, budget, threshold, EBOPS
|
|
116
115
|
print_quantization(model) # per-layer bit-width distribution and EBOPS
|
|
117
116
|
plot_quantization(model)
|
|
118
117
|
|
|
119
118
|
ir = model.get_layer('input_reduce')
|
|
120
|
-
print(f"
|
|
119
|
+
print(f"n_max_pixels={ir.n_max_pixels}, threshold={ir.threshold:.3f}")
|
|
121
120
|
```
|
|
122
121
|
|
|
123
122
|
## Converting a trained model to HLS with hls4ml
|
|
@@ -128,13 +127,31 @@ print(f"deploy with n_max_pixels={ir.n_max_pixels}, threshold={ir.threshold:.3f}
|
|
|
128
127
|
> pip install "git+https://github.com/hftsoi/hls4ml.git@sparsepixels"
|
|
129
128
|
> ```
|
|
130
129
|
|
|
131
|
-
Once installed,
|
|
130
|
+
Once installed, pull a config from the trained model, optionally set the per-layer parallelization
|
|
131
|
+
knobs, and convert:
|
|
132
132
|
|
|
133
133
|
```python
|
|
134
134
|
import hls4ml
|
|
135
135
|
|
|
136
136
|
hls_config = hls4ml.utils.config_from_keras_model(model, granularity='name')
|
|
137
|
-
hls_config.setdefault('Model', {})['PipelineStyle'] = 'dataflow' #
|
|
137
|
+
hls_config.setdefault('Model', {})['PipelineStyle'] = 'dataflow' # "#pragma HLS DATAFLOW"
|
|
138
|
+
|
|
139
|
+
# Optional per-layer parallelization knobs. Omit them for the fully-parallel, lowest-latency default.
|
|
140
|
+
# input_reduce Variant : 'tree' (default, lowest latency) or 'stream' (fewer resources)
|
|
141
|
+
# conv* PixelParallelFactor : active pixels in parallel (<= n_max_pixels)
|
|
142
|
+
# FiltParallelFactor : filters in parallel (<= that conv's filters)
|
|
143
|
+
# pool* PixelParallelFactor : active pixels in parallel
|
|
144
|
+
# ChanParallelFactor : channels in parallel
|
|
145
|
+
# flatten ParallelFactor : scatter positions in parallel (<= out_height * out_width)
|
|
146
|
+
n_sparse = model.get_layer('input_reduce').n_max_pixels
|
|
147
|
+
knobs = {
|
|
148
|
+
'input_reduce': {'Variant': 'stream'},
|
|
149
|
+
'conv1': {'PixelParallelFactor': n_sparse, 'FiltParallelFactor': 3},
|
|
150
|
+
'pool1': {'PixelParallelFactor': n_sparse, 'ChanParallelFactor': 3},
|
|
151
|
+
'flatten': {'ParallelFactor': 14 * 14}, # this model pools 28*28 -> 14*14
|
|
152
|
+
}
|
|
153
|
+
for name, cfg in knobs.items():
|
|
154
|
+
hls_config['LayerName'].setdefault(name, {}).update(cfg)
|
|
138
155
|
|
|
139
156
|
hls_model = hls4ml.converters.convert_from_keras_model(
|
|
140
157
|
model,
|
|
@@ -49,9 +49,10 @@ def set_sparse_ebops_factor(model):
|
|
|
49
49
|
HGQ counts a conv's EBOPS as if it ran over the whole H*W feature map, which overestimates a
|
|
50
50
|
sparse conv that only touches about n_max_pixels of them. This scales each sparse conv's EBOPS by
|
|
51
51
|
n_max_pixels / (H*W) through HGQ's own ebops_factor, so both the reported EBOPS and the EBOPS
|
|
52
|
-
regularization loss reflect the sparse compute.
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
regularization loss reflect the sparse compute. SparseTrainingMonitor applies this automatically
|
|
53
|
+
at the start of training, so you usually do not need to call it directly -- call it manually only
|
|
54
|
+
to correct EBOPS you inspect before training, or to refresh it if a learnable budget moves a lot
|
|
55
|
+
(it uses the current n_max_pixels, a good approximation since the budget moves slowly).
|
|
55
56
|
|
|
56
57
|
Returns a dict of {layer_name: factor} for the sparse convs that were adjusted.
|
|
57
58
|
"""
|
|
@@ -157,12 +158,19 @@ class SparseTrainingMonitor(Callback):
|
|
|
157
158
|
|
|
158
159
|
- n_max_pixels and threshold: the learned or fixed pixel budget and threshold of the InputReduce
|
|
159
160
|
layer (suffixed with the layer name when there is more than one).
|
|
160
|
-
- ebops: total EBOPS over the quantized layers, a proxy for the quantized hardware cost
|
|
161
|
-
|
|
161
|
+
- ebops: total EBOPS over the quantized layers, a proxy for the quantized hardware cost. This
|
|
162
|
+
monitor applies set_sparse_ebops_factor at the start of training, so the EBOPS (and its
|
|
163
|
+
regularizer) reflect the sparse (active-pixel) compute without any manual call.
|
|
162
164
|
- loss_task, loss_ebops, loss_n: the training loss split into the task loss, the EBOPS penalty and
|
|
163
165
|
the pixel-budget penalty, each already scaled by its weight so the three add up to the loss.
|
|
164
166
|
"""
|
|
165
167
|
|
|
168
|
+
def on_train_begin(self, logs=None):
|
|
169
|
+
# Fold in set_sparse_ebops_factor so the user need not call it manually. Uses the current
|
|
170
|
+
# (initial) budget, matching a manual call right before fit; call it again yourself if a
|
|
171
|
+
# learnable budget moves a lot during training.
|
|
172
|
+
set_sparse_ebops_factor(self.model)
|
|
173
|
+
|
|
166
174
|
def on_epoch_end(self, epoch, logs=None):
|
|
167
175
|
if logs is None:
|
|
168
176
|
return
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sparsepixels
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Efficient convolution for sparse data on FPGAs
|
|
5
5
|
Home-page: https://github.com/hftsoi/sparse-pixels
|
|
6
6
|
Author: Ho Fung Tsoi
|
|
@@ -47,20 +47,16 @@ pip install sparsepixels
|
|
|
47
47
|
|
|
48
48
|
## Getting Started
|
|
49
49
|
|
|
50
|
-
Import the sparse layers, the quantization library (HGQ2), and the training utilities:
|
|
51
|
-
|
|
52
50
|
```python
|
|
53
51
|
import keras
|
|
54
52
|
from keras.layers import Flatten, Activation
|
|
55
|
-
from hgq.layers import
|
|
53
|
+
from hgq.layers import QDense
|
|
56
54
|
from hgq.config import QuantizerConfigScope, LayerConfigScope
|
|
57
55
|
from hgq.quantizer.config import QuantizerConfig
|
|
58
56
|
from sparsepixels.layers import InputReduce, QConv2DSparse, AveragePooling2DSparse, MaxPooling2DSparse
|
|
59
57
|
from sparsepixels.utils import (
|
|
60
|
-
active_pixels_vs_threshold, plot_reduced_examples,
|
|
61
|
-
|
|
62
|
-
SparseTrainingMonitor, plot_history,
|
|
63
|
-
print_quantization, plot_quantization,
|
|
58
|
+
active_pixels_vs_threshold, plot_reduced_examples, cosine_lr,
|
|
59
|
+
SparseTrainingMonitor, plot_history, print_quantization, plot_quantization,
|
|
64
60
|
)
|
|
65
61
|
```
|
|
66
62
|
|
|
@@ -112,31 +108,34 @@ with (
|
|
|
112
108
|
model = keras.Model(x_in, x)
|
|
113
109
|
```
|
|
114
110
|
|
|
115
|
-
Train the model
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
`layer.threshold`.
|
|
111
|
+
Train the model with `SparseTrainingMonitor`. It records the loss breakdown, the learned
|
|
112
|
+
budget/threshold and the EBOPS each epoch, and it corrects the EBOPS (a proxy for the quantized
|
|
113
|
+
hardware cost) to the sparse compute automatically, so no extra setup is needed. The
|
|
114
|
+
only sparse-specific choices are the cosine-decayed learning rate and `restore_best_weights`, which
|
|
115
|
+
keep the learned budget from over-compressing near the end of training.
|
|
121
116
|
|
|
122
117
|
```python
|
|
123
|
-
set_sparse_ebops_factor(model)
|
|
124
|
-
|
|
125
|
-
steps_per_epoch = len(x_train) // 128
|
|
126
118
|
early_stop = keras.callbacks.EarlyStopping(monitor='val_accuracy', mode='max', patience=20, restore_best_weights=True)
|
|
127
119
|
model.compile(
|
|
128
|
-
optimizer=keras.optimizers.Adam(cosine_lr(1e-3, epochs=100, steps_per_epoch=
|
|
120
|
+
optimizer=keras.optimizers.Adam(cosine_lr(1e-3, epochs=100, steps_per_epoch=len(x_train) // 128)),
|
|
129
121
|
loss='categorical_crossentropy', metrics=['accuracy'],
|
|
130
122
|
)
|
|
131
123
|
history = model.fit(x_train, y_train, validation_data=(x_val, y_val),
|
|
132
124
|
epochs=100, batch_size=128, callbacks=[early_stop, SparseTrainingMonitor()])
|
|
125
|
+
```
|
|
133
126
|
|
|
127
|
+
After training, plot the diagnostics and read out the learned sparsity to deploy. `plot_history`
|
|
128
|
+
shows the loss breakdown, the learned budget/threshold and the EBOPS in one figure.
|
|
129
|
+
`print_quantization` / `plot_quantization` summarize the per-layer bit-widths. The values to
|
|
130
|
+
deploy are `layer.n_max_pixels` and `layer.threshold` (hls4ml converter will auto-parse these from the model).
|
|
131
|
+
|
|
132
|
+
```python
|
|
134
133
|
plot_history(history, early_stopping=early_stop) # loss breakdown, budget, threshold, EBOPS
|
|
135
134
|
print_quantization(model) # per-layer bit-width distribution and EBOPS
|
|
136
135
|
plot_quantization(model)
|
|
137
136
|
|
|
138
137
|
ir = model.get_layer('input_reduce')
|
|
139
|
-
print(f"
|
|
138
|
+
print(f"n_max_pixels={ir.n_max_pixels}, threshold={ir.threshold:.3f}")
|
|
140
139
|
```
|
|
141
140
|
|
|
142
141
|
## Converting a trained model to HLS with hls4ml
|
|
@@ -147,13 +146,31 @@ print(f"deploy with n_max_pixels={ir.n_max_pixels}, threshold={ir.threshold:.3f}
|
|
|
147
146
|
> pip install "git+https://github.com/hftsoi/hls4ml.git@sparsepixels"
|
|
148
147
|
> ```
|
|
149
148
|
|
|
150
|
-
Once installed,
|
|
149
|
+
Once installed, pull a config from the trained model, optionally set the per-layer parallelization
|
|
150
|
+
knobs, and convert:
|
|
151
151
|
|
|
152
152
|
```python
|
|
153
153
|
import hls4ml
|
|
154
154
|
|
|
155
155
|
hls_config = hls4ml.utils.config_from_keras_model(model, granularity='name')
|
|
156
|
-
hls_config.setdefault('Model', {})['PipelineStyle'] = 'dataflow' #
|
|
156
|
+
hls_config.setdefault('Model', {})['PipelineStyle'] = 'dataflow' # "#pragma HLS DATAFLOW"
|
|
157
|
+
|
|
158
|
+
# Optional per-layer parallelization knobs. Omit them for the fully-parallel, lowest-latency default.
|
|
159
|
+
# input_reduce Variant : 'tree' (default, lowest latency) or 'stream' (fewer resources)
|
|
160
|
+
# conv* PixelParallelFactor : active pixels in parallel (<= n_max_pixels)
|
|
161
|
+
# FiltParallelFactor : filters in parallel (<= that conv's filters)
|
|
162
|
+
# pool* PixelParallelFactor : active pixels in parallel
|
|
163
|
+
# ChanParallelFactor : channels in parallel
|
|
164
|
+
# flatten ParallelFactor : scatter positions in parallel (<= out_height * out_width)
|
|
165
|
+
n_sparse = model.get_layer('input_reduce').n_max_pixels
|
|
166
|
+
knobs = {
|
|
167
|
+
'input_reduce': {'Variant': 'stream'},
|
|
168
|
+
'conv1': {'PixelParallelFactor': n_sparse, 'FiltParallelFactor': 3},
|
|
169
|
+
'pool1': {'PixelParallelFactor': n_sparse, 'ChanParallelFactor': 3},
|
|
170
|
+
'flatten': {'ParallelFactor': 14 * 14}, # this model pools 28*28 -> 14*14
|
|
171
|
+
}
|
|
172
|
+
for name, cfg in knobs.items():
|
|
173
|
+
hls_config['LayerName'].setdefault(name, {}).update(cfg)
|
|
157
174
|
|
|
158
175
|
hls_model = hls4ml.converters.convert_from_keras_model(
|
|
159
176
|
model,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|