Skip to content

Commit 3ed9193

Browse files
authored
For encoded convolution, add check for when min_width would have been larger than in_width (#610)
* add special case when W == min_width. * add test that fails without this fix * add comments * Make simple bug fixes before reworking structure * Try to cleanup how we handle the narrow convolutions * fix hardcoded returns * update convolution templates for narrow encoded * flake8 formatting * update narrow for conv2d, fix test * change narrow to unscaled, always do unscaled when in_W == min_W * pre-commit fixes for nnet_conv1d_stream.h and nnet_conv2d_stream.h * remove unneeded attributes * change hardcoded instructions condition
1 parent 4d326d5 commit 3ed9193

File tree

8 files changed

+514
-238
lines changed

8 files changed

+514
-238
lines changed

hls4ml/backends/fpga/fpga_backend.py

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,10 @@ def compute_conv1d_instructions(self, in_W, in_C, kernel_size=3, stride=1, pad=0
394394
else:
395395
min_W = (math.ceil(stride / kernel_size) - 1) * stride + kernel_size
396396

397+
# if the standard min_W is smaller than the in_W, then use unscaled
398+
if min_W > in_W:
399+
min_W = in_W
400+
397401
min_oW = int((min_W - kernel_size) // stride + 1)
398402

399403
out_W = int((in_W - kernel_size) // stride + 1)
@@ -442,11 +446,17 @@ def compute_conv2d_instructions(self, in_H, in_W, in_C, kernel_size=3, stride=1,
442446
else:
443447
min_H = (math.ceil(stride_height / kernel_height) - 1) * stride_height + kernel_height
444448

449+
if min_H > in_H:
450+
min_H = in_H
451+
445452
if kernel_width >= stride_width:
446453
min_W = (math.ceil(kernel_width / stride_width) - 1) * stride_width + kernel_width
447454
else:
448455
min_W = (math.ceil(stride_width / kernel_width) - 1) * stride_width + kernel_width
449456

457+
if min_W > in_W:
458+
min_W = in_W
459+
450460
min_oH = int((min_H - kernel_height) // stride_height + 1)
451461
min_oW = int((min_W - kernel_width) // stride_width + 1)
452462

@@ -461,9 +471,25 @@ def compute_conv2d_instructions(self, in_H, in_W, in_C, kernel_size=3, stride=1,
461471
min_W += 1
462472

463473
# Let's hardcode a few common cases:
464-
if kernel_height == 1 and kernel_width == 1 and stride == 1 and scaled_H == in_H and scaled_W == in_W:
474+
if (
475+
min_H == 1
476+
and min_W == 1
477+
and kernel_height == 1
478+
and kernel_width == 1
479+
and stride == 1
480+
and scaled_H == in_H
481+
and scaled_W == in_W
482+
):
465483
return (1, 1, map(str, [1]))
466-
if kernel_height == 3 and kernel_width == 3 and stride == 1 and scaled_H == in_H and scaled_W == in_W:
484+
if (
485+
min_H == 5
486+
and min_W == 5
487+
and kernel_height == 3
488+
and kernel_width == 3
489+
and stride == 1
490+
and scaled_H == in_H
491+
and scaled_W == in_W
492+
):
467493
return (
468494
5,
469495
5,
@@ -498,7 +524,15 @@ def compute_conv2d_instructions(self, in_H, in_W, in_C, kernel_size=3, stride=1,
498524
],
499525
),
500526
)
501-
if kernel_height == 5 and kernel_width == 5 and stride == 1 and scaled_H == in_H and scaled_W == in_W:
527+
if (
528+
min_H == 9
529+
and min_W == 9
530+
and kernel_height == 5
531+
and kernel_width == 5
532+
and stride == 1
533+
and scaled_H == in_H
534+
and scaled_W == in_W
535+
):
502536
return (
503537
9,
504538
9,

hls4ml/backends/vivado/passes/conv_stream.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
from hls4ml.model.layers import Conv1D, Conv2D, SeparableConv1D, SeparableConv2D
12
from hls4ml.model.optimizer import OptimizerPass
2-
from hls4ml.model.layers import Conv1D, SeparableConv1D, Conv2D, SeparableConv2D
3+
34

45
class GenerateConvStreamingInstructions(OptimizerPass):
5-
''' Generates the instructions for streaming implementation of CNNs '''
6+
'''Generates the instructions for streaming implementation of CNNs'''
7+
68
def match(self, node):
79
return isinstance(node, (Conv1D, SeparableConv1D, Conv2D, SeparableConv2D))
810

@@ -13,19 +15,21 @@ def transform(self, model, node):
1315
elif '2D' in node_class:
1416
self._generate_2d_instructions(node)
1517
else:
16-
raise Exception('Cannot generate instructions for node {} ({})'.format(node.name, node_class))
17-
18+
raise Exception(f'Cannot generate instructions for node {node.name} ({node_class})')
19+
1820
def _generate_1d_instructions(self, node):
1921
if node.model.config.get_config_value('IOType') == 'io_stream':
2022
min_w, instructions = node.model.config.backend.compute_conv1d_instructions(
2123
node.get_input_variable().shape[0],
2224
node.get_input_variable().shape[1],
2325
node.get_attr('filt_width'),
24-
node.get_attr('stride_width'))
26+
node.get_attr('stride_width'),
27+
)
2528
instructions_str = ','.join(str(i) for i in instructions)
2629
node.set_attr('min_width', min_w)
2730
node.set_attr('instructions', instructions_str)
2831
else:
32+
# these are unused; just put dummy values
2933
node.set_attr('min_width', node.get_attr('in_width'))
3034
node.set_attr('instructions', '0')
3135

@@ -36,7 +40,8 @@ def _generate_2d_instructions(self, node):
3640
node.get_input_variable().shape[1],
3741
node.get_input_variable().shape[2],
3842
node.get_attr('filt_height'),
39-
node.get_attr('stride_height'))
43+
node.get_attr('stride_height'),
44+
)
4045
instructions_str = ','.join(str(i) for i in instructions)
4146
node.set_attr('min_height', min_h)
4247
node.set_attr('min_width', min_w)

0 commit comments

Comments
 (0)