1
- import numpy as np
2
1
from copy import copy
3
2
4
- from hls4ml . model . optimizer import OptimizerPass
5
- from hls4ml . model . layers import register_layer
3
+ import numpy as np
4
+
6
5
from hls4ml .backends .fpga .fpga_layers import PointwiseConv1D , PointwiseConv2D
7
- from hls4ml .backends .quartus .passes .convolution_templates import Conv1DConfigTemplate , Conv1DFunctionTemplate , Conv2DConfigTemplate , Conv2DFunctionTemplate , conv1d_config_template , conv2d_config_template , conv_mult_config_template
6
+ from hls4ml .backends .quartus .passes .convolution_templates import (
7
+ Conv1DConfigTemplate ,
8
+ Conv1DFunctionTemplate ,
9
+ Conv2DConfigTemplate ,
10
+ Conv2DFunctionTemplate ,
11
+ conv1d_config_template ,
12
+ conv2d_config_template ,
13
+ conv_mult_config_template ,
14
+ )
15
+ from hls4ml .model .layers import register_layer
16
+ from hls4ml .model .optimizer import OptimizerPass
8
17
9
18
'''
10
19
Custom hls4ml layer implementation for 1x1 Conv filters using im2col
11
20
Allows lower latency andresource usage, due to less loop invocations
12
21
'''
13
22
14
- pointwise_conv1d_function_template = 'nnet::pointwise_conv_1d_{data_format}<{input_t}, {output_t}, {config}>({input}, {output}, {w}, {b});'
15
- pointwise_conv2d_function_template = 'nnet::pointwise_conv_2d_{data_format}<{input_t}, {output_t}, {config}>({input}, {output}, {w}, {b});'
23
+ pointwise_conv1d_function_template = (
24
+ 'nnet::pointwise_conv_1d_{data_format}<{input_t}, {output_t}, {config}>({input}, {output}, {w}, {b});'
25
+ )
26
+ pointwise_conv2d_function_template = (
27
+ 'nnet::pointwise_conv_2d_{data_format}<{input_t}, {output_t}, {config}>({input}, {output}, {w}, {b});'
28
+ )
16
29
17
30
sepconv1d_include_list = ['nnet_utils/nnet_conv1d.h' ]
18
31
sepconv2d_include_list = ['nnet_utils/nnet_conv2d.h' ]
19
32
33
+
20
34
class PointwiseConv1DConfigTemplate (Conv1DConfigTemplate ):
21
35
def __init__ (self ):
22
36
super (Conv1DConfigTemplate , self ).__init__ (PointwiseConv1D )
23
37
self .template = conv1d_config_template
24
38
self .mult_template = conv_mult_config_template
25
39
40
+
26
41
class PointwiseConv1DFunctionTemplate (Conv1DFunctionTemplate ):
27
42
def __init__ (self ):
28
43
super (Conv1DFunctionTemplate , self ).__init__ (PointwiseConv1D , include_header = sepconv1d_include_list )
29
44
self .template = pointwise_conv1d_function_template
30
45
46
+
31
47
class PointwiseConv2DConfigTemplate (Conv2DConfigTemplate ):
32
48
def __init__ (self ):
33
49
super (Conv2DConfigTemplate , self ).__init__ (PointwiseConv2D )
34
50
self .template = conv2d_config_template
35
51
self .mult_template = conv_mult_config_template
36
52
53
+
37
54
class PointwiseConv2DFunctionTemplate (Conv2DFunctionTemplate ):
38
55
def __init__ (self ):
39
56
super (Conv2DFunctionTemplate , self ).__init__ (PointwiseConv2D , include_header = sepconv2d_include_list )
@@ -54,19 +71,25 @@ def register_pointwise(backend):
54
71
backend .register_template (PointwiseConv2DConfigTemplate )
55
72
backend .register_template (PointwiseConv2DFunctionTemplate )
56
73
74
+
57
75
class OptimizePointwiseConv (OptimizerPass ):
58
76
def match (self , node ):
59
- return node .class_name in ('Conv1D' , 'Conv2D' ) and \
60
- node .get_attr ('filt_height' , 1 ) == 1 and \
61
- node .get_attr ('filt_width' ) == 1 and \
62
- node .model .config .get_config_value ('IOType' ) == 'io_parallel'
77
+ return (
78
+ node .class_name in ('Conv1D' , 'Conv2D' )
79
+ and node .get_attr ('filt_height' , 1 ) == 1
80
+ and node .get_attr ('filt_width' ) == 1
81
+ and node .model .config .get_config_value ('IOType' ) == 'io_parallel'
82
+ )
63
83
64
84
def transform (self , model , node ):
65
- dim = node .__class__ .__name__ [- 2 :] # '1D' or '2D'
66
- pw_node = model .make_node ('PointwiseConv' + dim , node .name , copy (node .attributes ), node .inputs .copy (), outputs = node .outputs .copy ())
67
- if len (node .weights ['weight' ].data .shape ) == 2 : # This can happen if we assign weights of Dense layer to 1x1 Conv2D
68
- pw_node .weights ['weight' ].data = np .expand_dims (node .weights ['weight' ].data , axis = (0 ,1 ))
85
+ dim = node .__class__ .__name__ [- 2 :] # '1D' or '2D'
86
+ pw_node = model .make_node (
87
+ 'PointwiseConv' + dim , node .name , copy (node .attributes ), node .inputs .copy (), outputs = node .outputs .copy ()
88
+ )
89
+ if len (node .weights ['weight' ].data .shape ) == 2 : # This can happen if we assign weights of Dense layer to 1x1 Conv2D
90
+ expand_axis = tuple (range (int (dim [0 ])))
91
+ pw_node .weights ['weight' ].data = np .expand_dims (node .weights ['weight' ].data , axis = expand_axis )
69
92
pw_node .weights ['bias' ].data = node .weights ['bias' ].data
70
93
model .replace_node (node , pw_node )
71
-
94
+
72
95
return True
0 commit comments