4848from torch .nn import Parameter
4949
5050
51+ # The arguments of the conv are:
52+ # convolution(
53+ # Tensor input, Tensor weight, Tensor? bias,
54+ # SymInt[] stride, SymInt[] padding, SymInt[] dilation,
55+ # bool transposed, SymInt[] output_padding, SymInt groups
56+ # ) -> Tensor
57+ Stride = Padding = Dilation = OutPadding = list [int ]
58+ Transposed = bool
59+ Groups = int
60+ ConvolutionArgs = tuple [
61+ Node , Node , Node | None , Stride , Padding , Dilation , Transposed , OutPadding , Groups
62+ ]
63+
64+
5165class ConvolutionConverter (NodeConverter ):
66+ @staticmethod
67+ def _is_supported_on_target_new_flow (
68+ node : Node ,
69+ parameters_mapping : dict [str , Parameter ],
70+ ) -> bool :
71+ (
72+ inp_node ,
73+ w_node ,
74+ b_node ,
75+ stride ,
76+ padding ,
77+ dilation ,
78+ transposed ,
79+ _ ,
80+ groups ,
81+ ) = ConvolutionConverter ._get_convolution_arguments (node )
82+
83+ # Input must be INT8/UINT8
84+ # Output must be INT8/UINT8
85+ inp_out_supported_types = [torch .int8 , torch .uint8 ]
86+ if not NodeConverter .uses_quantization_type_for_io (
87+ node , inp_out_supported_types , [0 ], [0 ]
88+ ):
89+ return False
90+
91+ # Weights must be INT8
92+ w_supported_types = [torch .int8 ]
93+ if not NodeConverter .uses_quantization_type_for_io (
94+ node , w_supported_types , [1 ], []
95+ ):
96+ return False
97+
98+ # Bias must be INT32
99+ if b_node is not None :
100+ b_supported_types = [torch .int32 ]
101+ if not NodeConverter .uses_quantization_type_for_io (
102+ node , b_supported_types , [2 ], []
103+ ):
104+ return False
105+
106+ # Weights must be constant
107+ if not node_is_effectively_static_tensor (w_node , parameters_mapping ):
108+ return False
109+
110+ # Bias must be constant (if present)
111+ if b_node is not None and not node_is_effectively_static_tensor (
112+ b_node , parameters_mapping
113+ ):
114+ return False
115+
116+ # kernelH <= 4096, kernelW <= 4096
117+ # strideH <= 4096, strideW <= 4096
118+ # dilationH <= 4096, dilationW <= 4096
119+ w_node_shape = w_node .meta ["val" ].shape
120+
121+ kernel_h = w_node_shape [2 ]
122+ kernel_w = w_node_shape [3 ]
123+ stride_h = stride [0 ]
124+ stride_w = stride [1 ]
125+ dilation_h = dilation [0 ]
126+ dilation_w = dilation [1 ]
127+
128+ dim_sizes = [kernel_h , kernel_w , stride_h , stride_w , dilation_h , dilation_w ]
129+
130+ if any (dim > 4096 for dim in dim_sizes ):
131+ return False
132+
133+ # kernelH * kernelW * inpC <= 65535
134+ inp_node_shape = (
135+ inp_node .meta ["val" ].shape if hasattr (inp_node , "meta" ) else inp_node .shape
136+ )
137+ inp_channels = inp_node_shape [1 ]
138+
139+ if kernel_h * kernel_w * inp_channels > 65535 :
140+ return False
141+
142+ return True
143+
52144 @staticmethod
53145 def _is_supported_on_target (
54146 node : Node ,
55147 neutron_target_spec : NeutronTargetSpec ,
56148 parameters_mapping : dict [str , Parameter ],
57149 custom_delegation_options : CustomDelegationOptions ,
58150 ) -> bool :
151+ if custom_delegation_options .use_new_flow_neutron_c :
152+ return ConvolutionConverter ._is_supported_on_target_new_flow (
153+ node , parameters_mapping
154+ )
155+
59156 num_macs = neutron_target_spec .get_num_macs ()
60157 node_t_params = get_node_tensor_params (node )
61- weights = node .args [1 ]
62- conv_params = ConvParameters (
63- * ConvolutionConverter ._get_convolution_arguments (node )
158+ _ , w_node , _ , stride , padding , dilation , transposed , _ , groups = (
159+ ConvolutionConverter ._get_convolution_arguments (node )
64160 )
65161
66162 if node_t_params ["batch_size" ] != 1 :
67163 # Only batch size 1 is supported on neutron.
68164 return False
69165
70- if conv_params . transposed :
166+ if transposed :
71167 # TransposeConv2d with groups > 1 is not supported
72168 # TODO: split into multiple convs with groups = 1
73- if conv_params . groups > 1 :
169+ if groups > 1 :
74170 return False
75- if not node_is_effectively_static_tensor (weights , parameters_mapping ):
171+ if not node_is_effectively_static_tensor (w_node , parameters_mapping ):
76172 # Only supported if the weights are static, because TFLite `TransposeConv` uses permuted
77173 # weights. In case the weights are dynamic, a Transpose operator would have to be added, which
78174 # is not supported on Neutron.
79175 return False
80176 # neutron-library/src/utils/NeutronLibraryInterrogation.cpp#876 TransposeConv2DKernelKind
81177 if (
82- conv_params . dilation != [1 , 1 ]
83- or conv_params . padding [0 ] != 0
84- or conv_params . padding [1 ] >= node_t_params ["kernel_width" ]
178+ dilation != [1 , 1 ]
179+ or padding [0 ] != 0
180+ or padding [1 ] >= node_t_params ["kernel_width" ]
85181 or (
86- conv_params . padding [1 ] != 0 and node_t_params ["inp_height" ] != 1
182+ padding [1 ] != 0 and node_t_params ["inp_height" ] != 1
87183 ) # Slice added by explicit padding
88- or conv_params . stride [0 ] != 1
184+ or stride [0 ] != 1
89185 or (
90186 (
91- conv_params . stride [1 ] != node_t_params ["kernel_width" ] / 2
187+ stride [1 ] != node_t_params ["kernel_width" ] / 2
92188 or node_t_params ["out_height" ] != 1
93189 )
94- and conv_params . stride [1 ] != node_t_params ["kernel_width" ]
190+ and stride [1 ] != node_t_params ["kernel_width" ]
95191 )
96- or conv_params . stride [1 ] % 2 != 0
192+ or stride [1 ] % 2 != 0
97193 or node_t_params ["inp_channels" ] % num_macs != 0
98194 or node_t_params ["out_channels" ] % num_macs != 0
99195 or node_t_params ["kernel_width" ] % 2 != 0
100196 or node_t_params ["kernel_height" ] != 1
101197 ):
102198 return False
103- elif conv_params . groups == 1 : # Regular convolution.
199+ elif groups == 1 : # Regular convolution.
104200 pass
105201 elif conv_utils .group_conv_convertible_as_depthwise (
106- node , conv_params . groups
202+ node , groups
107203 ): # Depthwise convolution.
108204 # Only supported if the weights are static, because TFLite `DepthwiseConv2D` uses permuted
109205 # weights. In case the weights are dynamic, a Transpose operator would have to be added, which
110206 # is not supported on Neutron.
111- if not node_is_effectively_static_tensor (weights , parameters_mapping ):
207+ if not node_is_effectively_static_tensor (w_node , parameters_mapping ):
112208 return False
113209 elif conv_utils .group_conv_convertible_into_multiple_convolutions (
114- node , conv_params . groups
210+ node , groups
115211 ): # Separable conv.
116212 # Requires addition of `Split` and `Concatenation` operators, which are not supported on Neutron.
117213 return False
@@ -149,10 +245,6 @@ def _is_supported_in_IR(
149245
150246 return True
151247
152- Stride = Padding = Dilation = OutPadding = list [int ]
153- Transposed = bool
154- Groups = int
155-
156248 def _compute_slicing_params (
157249 self , output_shape , explicit_padding
158250 ) -> tuple [list [int ], list [int ]]:
@@ -170,14 +262,14 @@ def _compute_slicing_params(
170262 @staticmethod
171263 def _get_convolution_arguments (
172264 conv_node : Node ,
173- ) -> (Stride , Padding , Dilation , Transposed , OutPadding , Groups ):
174- # The arguments of the conv are:
175- # [x, w, b, stride, padding, dilation, transposed, output padding, groups]
176- # https://github.com/pytorch/pytorch/blob/v2.6.0/aten/src/ATen/native/Convolution.cpp#L286-L291
177- _ , _ , _ , stride , padding , dilation , transposed , out_padding , groups = (
265+ ) -> ConvolutionArgs :
266+ x , w , b , stride , padding , dilation , transposed , out_padding , groups = (
178267 conv_node .args
179268 )
180269 return (
270+ x ,
271+ w ,
272+ b ,
181273 list (stride ),
182274 list (padding ),
183275 list (dilation ),
@@ -380,16 +472,8 @@ def _convert_2d_conv(
380472
381473 elif conv_utils .group_conv_convertible_into_multiple_convolutions (
382474 t_op , conv_params .groups
383- ): # Convert to separated `Conv2D`.
384- t_op .builtin_options = conv_2d_options .Conv2D ()
385-
386- return conv_utils .create_separated_convolutions_based_on_group (
387- t_op ,
388- conv_params ,
389- self .builder ,
390- self ._convert_unpadded_2D ,
391- conv_utils .conv_op_factory ,
392- )
475+ ):
476+ raise RuntimeError ("NXP backend: Group convolution was not decomposed." )
393477
394478 else :
395479 # Convert to regular `Conv2D`.
@@ -419,7 +503,7 @@ def _convert_2d_conv(
419503 def convert (self , node : Node ):
420504 self .assert_convertible (node )
421505
422- stride , padding , dilation , transposed , out_padding , groups = (
506+ _ , _ , _ , stride , padding , dilation , transposed , out_padding , groups = (
423507 self ._get_convolution_arguments (node )
424508 )
425509
0 commit comments