Skip to content

Commit 3591ae5

Browse files
committed
Merge remote-tracking branch 'upstream/main' into qonnx-1p0
2 parents c3ffa7b + 1520518 commit 3591ae5

File tree

13 files changed

+274
-179
lines changed

13 files changed

+274
-179
lines changed

hls4ml/converters/__init__.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from hls4ml.converters.keras_to_hls import parse_keras_model # noqa: F401
1212
from hls4ml.converters.keras_to_hls import keras_to_hls, register_keras_layer_handler
1313
from hls4ml.converters.onnx_to_hls import parse_onnx_model # noqa: F401
14+
# from hls4ml.converters.pytorch_to_hls import parse_pytorch_model # noqa: F401
1415
from hls4ml.model import ModelGraph
1516
from hls4ml.utils.config import create_config
1617
from hls4ml.utils.symbolic_utils import LUTFunction
@@ -239,7 +240,6 @@ def convert_from_keras_model(
239240

240241
def convert_from_pytorch_model(
241242
model,
242-
input_shape,
243243
output_dir='my-hls-test',
244244
project_name='myproject',
245245
input_data_tb=None,
@@ -252,7 +252,6 @@ def convert_from_pytorch_model(
252252
253253
Args:
254254
model: PyTorch model to convert.
255-
input_shape (list): The shape of the input tensor. First element is the batch size, needs to be None
256255
output_dir (str, optional): Output directory of the generated HLS project. Defaults to 'my-hls-test'.
257256
project_name (str, optional): Name of the HLS project. Defaults to 'myproject'.
258257
input_data_tb (str, optional): String representing the path of input data in .npy or .dat format that will be
@@ -294,17 +293,16 @@ def convert_from_pytorch_model(
294293
config = create_config(output_dir=output_dir, project_name=project_name, backend=backend, **kwargs)
295294

296295
config['PytorchModel'] = model
297-
config['InputShape'] = input_shape
298296
config['InputData'] = input_data_tb
299297
config['OutputPredictions'] = output_data_tb
300298
config['HLSConfig'] = {}
301299

302300
if hls_config is None:
303301
hls_config = {}
304302

305-
model_config = hls_config.get('Model', None)
303+
model_config = hls_config.get('Model')
306304
config['HLSConfig']['Model'] = _check_model_config(model_config)
307-
305+
config['InputShape'] = hls_config.get('InputShape')
308306
_check_hls_config(config, hls_config)
309307

310308
return pytorch_to_hls(config)

hls4ml/converters/pytorch_to_hls.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def decorator(function):
102102
# ----------------------------------------------------------------
103103

104104

105-
def pytorch_to_hls(config):
105+
def parse_pytorch_model(config, verbose=True):
106106
"""Convert PyTorch model to hls4ml ModelGraph.
107107
108108
Args:
@@ -118,14 +118,15 @@ def pytorch_to_hls(config):
118118
# This is a list of dictionaries to hold all the layer info we need to generate HLS
119119
layer_list = []
120120

121-
print('Interpreting Model ...')
122-
121+
if verbose:
122+
print('Interpreting Model ...')
123123
reader = PyTorchFileReader(config) if isinstance(config['PytorchModel'], str) else PyTorchModelReader(config)
124124
if type(reader.input_shape) is tuple:
125125
input_shapes = [list(reader.input_shape)]
126126
else:
127127
input_shapes = list(reader.input_shape)
128-
input_shapes = [list(shape) for shape in input_shapes]
128+
# first element needs to 'None' as placeholder for the batch size, insert it if not present
129+
input_shapes = [[None] + list(shape) if shape[0] is not None else list(shape) for shape in input_shapes]
129130

130131
model = reader.torch_model
131132

@@ -151,7 +152,8 @@ def pytorch_to_hls(config):
151152
output_shape = None
152153

153154
# Loop through layers
154-
print('Topology:')
155+
if verbose:
156+
print('Topology:')
155157
layer_counter = 0
156158

157159
n_inputs = 0
@@ -226,13 +228,14 @@ def pytorch_to_hls(config):
226228
pytorch_class, layer_name, input_names, input_shapes, node, class_object, reader, config
227229
)
228230

229-
print(
230-
'Layer name: {}, layer type: {}, input shape: {}'.format(
231-
layer['name'],
232-
layer['class_name'],
233-
input_shapes,
231+
if verbose:
232+
print(
233+
'Layer name: {}, layer type: {}, input shape: {}'.format(
234+
layer['name'],
235+
layer['class_name'],
236+
input_shapes,
237+
)
234238
)
235-
)
236239
layer_list.append(layer)
237240

238241
assert output_shape is not None
@@ -288,7 +291,12 @@ def pytorch_to_hls(config):
288291
operation, layer_name, input_names, input_shapes, node, None, reader, config
289292
)
290293

291-
print('Layer name: {}, layer type: {}, input shape: {}'.format(layer['name'], layer['class_name'], input_shapes))
294+
if verbose:
295+
print(
296+
'Layer name: {}, layer type: {}, input shape: {}'.format(
297+
layer['name'], layer['class_name'], input_shapes
298+
)
299+
)
292300
layer_list.append(layer)
293301

294302
assert output_shape is not None
@@ -342,7 +350,12 @@ def pytorch_to_hls(config):
342350
operation, layer_name, input_names, input_shapes, node, None, reader, config
343351
)
344352

345-
print('Layer name: {}, layer type: {}, input shape: {}'.format(layer['name'], layer['class_name'], input_shapes))
353+
if verbose:
354+
print(
355+
'Layer name: {}, layer type: {}, input shape: {}'.format(
356+
layer['name'], layer['class_name'], input_shapes
357+
)
358+
)
346359
layer_list.append(layer)
347360

348361
assert output_shape is not None
@@ -351,6 +364,11 @@ def pytorch_to_hls(config):
351364
if len(input_layers) == 0:
352365
input_layers = None
353366

367+
return layer_list, input_layers
368+
369+
370+
def pytorch_to_hls(config):
371+
layer_list, input_layers = parse_pytorch_model(config)
354372
print('Creating HLS model')
355373
hls_model = ModelGraph(config, layer_list, inputs=input_layers)
356374
return hls_model

hls4ml/templates/catapult/nnet_utils/nnet_pooling.h

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,20 @@ void pooling1d_cl(data_T data[CONFIG_T::n_in * CONFIG_T::n_filt], res_T res[CONF
107107
// TODO partition the arrays according to the reuse factor
108108
const int limit = pool_op_limit_1d<CONFIG_T>();
109109
#pragma HLS ALLOCATION function instances=CONFIG_T::pool_op limit=limit
110-
// Add any necessary padding
111-
unsigned padded_width = CONFIG_T::n_in + CONFIG_T::pad_left + CONFIG_T::pad_right;
112-
if (CONFIG_T::pad_left == 0 && CONFIG_T::pad_right == 0) {
113-
padded_width -= padded_width - (padded_width / CONFIG_T::stride_width * CONFIG_T::stride_width);
114-
}
110+
// Add padding and reduce input width to area covered by pooling function
111+
static constexpr int full_padded_width = CONFIG_T::n_in + CONFIG_T::pad_left + CONFIG_T::pad_right;
112+
static constexpr int restricted_padded_width = full_padded_width / CONFIG_T::stride_width * CONFIG_T::stride_width;
115113

116114
for (int ff = 0; ff < CONFIG_T::n_filt; ff++) {
117115
// Loop over input image x in steps of stride
118-
for (int ii = 0; ii < padded_width; ii += CONFIG_T::stride_width) {
116+
for (int ii = 0; ii < restricted_padded_width; ii += CONFIG_T::stride_width) {
119117
data_T pool[CONFIG_T::pool_width];
120118
#pragma HLS ARRAY_PARTITION variable=pool complete dim=0
121119
// Keep track of number of pixels in image vs padding region
122120
unsigned img_overlap = 0;
123121
// Loop over pool window x
124122
for (int jj = 0; jj < CONFIG_T::stride_width; jj++) {
125-
if (ii + jj < CONFIG_T::pad_left || ii + jj >= (padded_width - CONFIG_T::pad_right)) {
123+
if (ii + jj < CONFIG_T::pad_left || ii + jj >= (full_padded_width - CONFIG_T::pad_right)) {
126124
// Add padding
127125
pool[jj] = pad_val<data_T, CONFIG_T::pool_op>();
128126
if (CONFIG_T::count_pad) {
@@ -211,19 +209,17 @@ void pooling2d_cl(data_T data[CONFIG_T::in_height * CONFIG_T::in_width * CONFIG_
211209
// TODO partition the arrays according to the reuse factor
212210
const int limit = pool_op_limit<CONFIG_T>();
213211
#pragma HLS ALLOCATION function instances=CONFIG_T::pool_op limit=limit
214-
// Add any necessary padding
215-
unsigned padded_height = CONFIG_T::in_height + CONFIG_T::pad_top + CONFIG_T::pad_bottom;
216-
unsigned padded_width = CONFIG_T::in_width + CONFIG_T::pad_left + CONFIG_T::pad_right;
217-
if (CONFIG_T::pad_top == 0 && CONFIG_T::pad_bottom == 0 && CONFIG_T::pad_left == 0 && CONFIG_T::pad_right == 0) {
218-
padded_height -= padded_height - (padded_height / CONFIG_T::stride_height * CONFIG_T::stride_height);
219-
padded_width -= padded_width - (padded_width / CONFIG_T::stride_width * CONFIG_T::stride_width);
220-
}
212+
// Add padding and reduce input width to area covered by pooling function
213+
static constexpr int full_padded_width = CONFIG_T::in_width + CONFIG_T::pad_left + CONFIG_T::pad_right;
214+
static constexpr int full_padded_height = CONFIG_T::in_height + CONFIG_T::pad_top + CONFIG_T::pad_bottom;
215+
static constexpr int restricted_padded_width = full_padded_width / CONFIG_T::stride_width * CONFIG_T::stride_width;
216+
static constexpr int restricted_padded_height = full_padded_height / CONFIG_T::stride_height * CONFIG_T::stride_height;
221217

222218
for (int ff = 0; ff < CONFIG_T::n_filt; ff++) {
223219
// Loop over input image y in steps of stride
224-
for (int ii = 0; ii < padded_height; ii += CONFIG_T::stride_height) {
220+
for (int ii = 0; ii < restricted_padded_height; ii += CONFIG_T::stride_height) {
225221
// Loop over input image x in steps of stride
226-
for (int jj = 0; jj < padded_width; jj += CONFIG_T::stride_width) {
222+
for (int jj = 0; jj < restricted_padded_width; jj += CONFIG_T::stride_width) {
227223
data_T pool[CONFIG_T::pool_height * CONFIG_T::pool_width];
228224
#pragma HLS ARRAY_PARTITION variable=pool complete dim=0
229225
// Keep track of number of pixels in image vs padding region
@@ -232,8 +228,8 @@ void pooling2d_cl(data_T data[CONFIG_T::in_height * CONFIG_T::in_width * CONFIG_
232228
for (int kk = 0; kk < CONFIG_T::stride_height; kk++) {
233229
// Loop over pool window x
234230
for (int ll = 0; ll < CONFIG_T::stride_width; ll++) {
235-
if (ii + kk < CONFIG_T::pad_top || ii + kk >= (padded_height - CONFIG_T::pad_bottom) ||
236-
jj + ll < CONFIG_T::pad_left || jj + ll >= (padded_width - CONFIG_T::pad_right)) {
231+
if (ii + kk < CONFIG_T::pad_top || ii + kk >= (full_padded_height - CONFIG_T::pad_bottom) ||
232+
jj + ll < CONFIG_T::pad_left || jj + ll >= (full_padded_width - CONFIG_T::pad_right)) {
237233
// Add padding
238234
pool[kk * CONFIG_T::stride_width + ll] = pad_val<data_T, CONFIG_T::pool_op>();
239235
if (CONFIG_T::count_pad) {
@@ -275,19 +271,17 @@ void pooling2d_cf(data_T data[CONFIG_T::in_height * CONFIG_T::in_width * CONFIG_
275271
// TODO partition the arrays according to the reuse factor
276272
const int limit = pool_op_limit<CONFIG_T>();
277273
#pragma HLS ALLOCATION function instances=CONFIG_T::pool_op limit=limit
278-
// Add any necessary padding
279-
unsigned padded_height = CONFIG_T::in_height + CONFIG_T::pad_top + CONFIG_T::pad_bottom;
280-
unsigned padded_width = CONFIG_T::in_width + CONFIG_T::pad_left + CONFIG_T::pad_right;
281-
if (CONFIG_T::pad_top == 0 && CONFIG_T::pad_bottom == 0 && CONFIG_T::pad_left == 0 && CONFIG_T::pad_right == 0) {
282-
padded_height -= padded_height - (padded_height / CONFIG_T::stride_height * CONFIG_T::stride_height);
283-
padded_width -= padded_width - (padded_width / CONFIG_T::stride_width * CONFIG_T::stride_width);
284-
}
274+
// Add padding and reduce input width to area covered by pooling function
275+
static constexpr int full_padded_width = CONFIG_T::in_width + CONFIG_T::pad_left + CONFIG_T::pad_right;
276+
static constexpr int full_padded_height = CONFIG_T::in_height + CONFIG_T::pad_top + CONFIG_T::pad_bottom;
277+
static constexpr int restricted_padded_width = full_padded_width / CONFIG_T::stride_width * CONFIG_T::stride_width;
278+
static constexpr int restricted_padded_height = full_padded_height / CONFIG_T::stride_height * CONFIG_T::stride_height;
285279

286280
for (int ff = 0; ff < CONFIG_T::n_filt; ff++) {
287281
// Loop over input image y in steps of stride
288-
for (int ii = 0; ii < padded_height; ii += CONFIG_T::stride_height) {
282+
for (int ii = 0; ii < restricted_padded_height; ii += CONFIG_T::stride_height) {
289283
// Loop over input image x in steps of stride
290-
for (int jj = 0; jj < padded_width; jj += CONFIG_T::stride_width) {
284+
for (int jj = 0; jj < restricted_padded_width; jj += CONFIG_T::stride_width) {
291285
data_T pool[CONFIG_T::pool_height * CONFIG_T::pool_width];
292286
#pragma HLS ARRAY_PARTITION variable=pool complete dim=0
293287
// Keep track of number of pixels in image vs padding region
@@ -296,8 +290,8 @@ void pooling2d_cf(data_T data[CONFIG_T::in_height * CONFIG_T::in_width * CONFIG_
296290
for (int kk = 0; kk < CONFIG_T::stride_height; kk++) {
297291
// Loop over pool window x
298292
for (int ll = 0; ll < CONFIG_T::stride_width; ll++) {
299-
if (ii + kk < CONFIG_T::pad_top || ii + kk >= (padded_height - CONFIG_T::pad_bottom) ||
300-
jj + ll < CONFIG_T::pad_left || jj + ll >= (padded_width - CONFIG_T::pad_right)) {
293+
if (ii + kk < CONFIG_T::pad_top || ii + kk >= (full_padded_height - CONFIG_T::pad_bottom) ||
294+
jj + ll < CONFIG_T::pad_left || jj + ll >= (full_padded_width - CONFIG_T::pad_right)) {
301295
// Add padding
302296
pool[kk * CONFIG_T::stride_width + ll] = pad_val<data_T, CONFIG_T::pool_op>();
303297
if (CONFIG_T::count_pad) {

0 commit comments

Comments
 (0)