@@ -10,6 +10,74 @@ namespace converters {
1010namespace impl {
1111namespace {
1212
13+ void add_output_padding (nvinfer1::Dims& padding, nvinfer1::Dims& out_padding, bool & has_output_padding) {
14+ int nbSpatialDims = out_padding.nbDims ;
15+ // When there is out_padding, if padding is larger than out_padding, just adjust padding Or reduce out_padding as
16+ // minimum as possible.
17+ for (int i = 0 ; i < nbSpatialDims; ++i) {
18+ if (padding.d [i] - out_padding.d [i] >= 0 ) {
19+ padding.d [i] -= out_padding.d [i];
20+ out_padding.d [i] = 0 ;
21+ } else {
22+ // Reduce out_padding as possible.
23+ out_padding.d [i] -= padding.d [i];
24+ padding.d [i] = 0 ;
25+ has_output_padding = true ;
26+ }
27+ }
28+ }
29+
30+ nvinfer1::ILayer* add_bias_layer (
31+ ConversionCtx* ctx,
32+ nvinfer1::ITensor* input_tensor,
33+ nvinfer1::Dims& input_dims,
34+ nvinfer1::Dims& output_padding,
35+ Weights& bias) {
36+ nvinfer1::ITensor* input_shape = ctx->net ->addShape (*input_tensor)->getOutput (0 );
37+ // Add padding layer
38+ nvinfer1::ITensor* start;
39+ nvinfer1::ITensor* totalPadding;
40+ auto in_nbDims = input_dims.nbDims ;
41+ std::vector<int32_t > startVec (in_nbDims, 0 );
42+ std::vector<int32_t > totalPaddingVec (in_nbDims, 0 );
43+ int32_t diff = in_nbDims - output_padding.nbDims ;
44+ for (int32_t i = diff; i < in_nbDims; i++) {
45+ int32_t idx = i - diff;
46+ startVec[i] = 0 ; // Don't need begin padding, only post padding
47+ totalPaddingVec[i] = output_padding.d [idx];
48+ }
49+ start = tensor_to_const (ctx, torch::tensor (startVec, torch::kInt32 ));
50+ totalPadding = tensor_to_const (ctx, torch::tensor (totalPaddingVec, torch::kInt32 ));
51+
52+ const auto size =
53+ ctx->net ->addElementWise (*input_shape, *totalPadding, nvinfer1::ElementWiseOperation::kSUM )->getOutput (0 );
54+
55+ nvinfer1::Dims stride;
56+ stride.nbDims = in_nbDims;
57+ for (int64_t i = 0 ; i < in_nbDims; i++) {
58+ stride.d [i] = 1 ;
59+ }
60+ const auto & dummy = stride;
61+ auto * sliceLayer = ctx->net ->addSlice (*input_tensor, dummy, dummy, stride);
62+ sliceLayer->setInput (1 , *start);
63+ sliceLayer->setInput (2 , *size);
64+ sliceLayer->setMode (nvinfer1::SliceMode::kFILL );
65+ nvinfer1::ITensor* slice_output = sliceLayer->getOutput (0 );
66+
67+ nvinfer1::Dims constantDims;
68+ constantDims.nbDims = in_nbDims;
69+ for (int64_t i = 0 ; i < in_nbDims; i++) {
70+ constantDims.d [i] = 1 ;
71+ }
72+ constantDims.d [diff - 1 ] =
73+ bias.shape .d [0 ]; // Set C dimension to bias dim and other dimensions to 1 to enable broadcast
74+ auto const_layer = ctx->net ->addConstant (constantDims, bias.data );
75+ auto bias_layer =
76+ ctx->net ->addElementWise (*slice_output, *const_layer->getOutput (0 ), nvinfer1::ElementWiseOperation::kSUM );
77+
78+ return bias_layer;
79+ }
80+
1381bool add_conv_deconv (ConversionCtx* ctx, const torch::jit::Node* n, args& args) {
1482 // Input to conv/deconv
1583 auto in = args[0 ].ITensor ();
@@ -76,16 +144,29 @@ bool add_conv_deconv(ConversionCtx* ctx, const torch::jit::Node* n, args& args)
76144
77145 nvinfer1::ILayer* layer = nullptr ;
78146 if (transposed) {
79- nvinfer1::IDeconvolutionLayer* deconvLayer =
80- ctx->net ->addDeconvolutionNd (*in, kernel_dims.d [0 ], filter_dim, kernel_weights, bias.data );
147+ // Fix padding based on output_padding provided
148+ nvinfer1::Dims begPadding = padding;
149+ bool hasOutputPadding = false ;
150+ add_output_padding (padding, out_padding, hasOutputPadding);
151+
152+ nvinfer1::IDeconvolutionLayer* deconvLayer = ctx->net ->addDeconvolutionNd (
153+ *in, kernel_dims.d [0 ], filter_dim, kernel_weights, hasOutputPadding ? nvinfer1::Weights{} : bias.data );
81154 deconvLayer->setStrideNd (stride);
82155 deconvLayer->setDilationNd (dilation);
83156 deconvLayer->setNbGroups (groups);
84- deconvLayer->setPaddingNd (padding);
157+ deconvLayer->setPrePadding (begPadding);
158+ deconvLayer->setPostPadding (padding);
159+
85160 // Set deconv kernel weights
86161 deconvLayer->setInput (1 , *kernel);
87162 TORCHTRT_CHECK (deconvLayer, " Unable to create deconv layer with non-const weights from node: " << *n);
88163 layer = deconvLayer;
164+ if (hasOutputPadding) {
165+ LOG_DEBUG (" Padding output deconvolution tensor with:" << out_padding);
166+ nvinfer1::ITensor* tensorPtr = deconvLayer->getOutput (0 );
167+ auto dims = in->getDimensions ();
168+ layer = add_bias_layer (ctx, tensorPtr, dims, out_padding, bias);
169+ }
89170 } else {
90171 nvinfer1::IConvolutionLayer* convLayer =
91172 ctx->net ->addConvolutionNd (*in, kernel_dims.d [0 ], filter_dim, kernel_weights, bias.data );
@@ -155,20 +236,7 @@ bool add_conv_deconv(ConversionCtx* ctx, const torch::jit::Node* n, args& args)
155236 // https://github.com/onnx/onnx-tensorrt/blob/c3cfcbc8248c6bd007e6630af2085df5e4834b42/builtin_op_importers.cpp#L734
156237 nvinfer1::Dims begPadding = padding;
157238 bool hasOutputPadding = false ;
158- int nbSpatialDims = out_padding.nbDims ;
159- // When there is out_padding, if padding is larger than out_padding, just adjust padding Or reduce out_padding as
160- // minimum as possible.
161- for (int i = 0 ; i < nbSpatialDims; ++i) {
162- if (padding.d [i] - out_padding.d [i] >= 0 ) {
163- padding.d [i] -= out_padding.d [i];
164- out_padding.d [i] = 0 ;
165- } else {
166- // Reduce out_padding as possible.
167- out_padding.d [i] -= padding.d [i];
168- padding.d [i] = 0 ;
169- hasOutputPadding = true ;
170- }
171- }
239+ add_output_padding (padding, out_padding, hasOutputPadding);
172240
173241 // shape of deconvolution's weight: [in, out/groups, ...]
174242 // If there is still output padding, remove the bias. Bias will be added below.
@@ -190,51 +258,8 @@ bool add_conv_deconv(ConversionCtx* ctx, const torch::jit::Node* n, args& args)
190258#endif
191259 if (hasOutputPadding) {
192260 LOG_DEBUG (" Padding output deconvolution tensor with:" << out_padding);
193-
194- // Add padding layer
195- nvinfer1::ITensor* start;
196- nvinfer1::ITensor* totalPadding;
197- auto in_nbDims = orig_dims.nbDims ;
198- std::vector<int32_t > startVec (in_nbDims, 0 );
199- std::vector<int32_t > totalPaddingVec (in_nbDims, 0 );
200- int32_t diff = in_nbDims - out_padding.nbDims ;
201- for (int32_t i = diff; i < in_nbDims; i++) {
202- int32_t idx = i - diff;
203- startVec[i] = 0 ; // Don't need begin padding, only post padding
204- totalPaddingVec[i] = out_padding.d [idx];
205- }
206- start = tensor_to_const (ctx, torch::tensor (startVec, torch::kInt32 ));
207- totalPadding = tensor_to_const (ctx, torch::tensor (totalPaddingVec, torch::kInt32 ));
208-
209261 nvinfer1::ITensor* tensorPtr = deconv->getOutput (0 );
210- nvinfer1::ITensor* deconvOutShape = ctx->net ->addShape (*tensorPtr)->getOutput (0 );
211- const auto size =
212- ctx->net ->addElementWise (*deconvOutShape, *totalPadding, nvinfer1::ElementWiseOperation::kSUM )->getOutput (0 );
213-
214- nvinfer1::Dims stride;
215- stride.nbDims = in_nbDims;
216- for (int64_t i = 0 ; i < in_nbDims; i++) {
217- stride.d [i] = 1 ;
218- }
219- const auto & dummy = stride;
220- auto * sliceLayer = ctx->net ->addSlice (*tensorPtr, dummy, dummy, stride);
221- sliceLayer->setInput (1 , *start);
222- sliceLayer->setInput (2 , *size);
223- sliceLayer->setMode (nvinfer1::SliceMode::kFILL );
224- tensorPtr = sliceLayer->getOutput (0 );
225-
226- nvinfer1::Dims constantDims;
227- constantDims.nbDims = in_nbDims;
228- for (int64_t i = 0 ; i < in_nbDims; i++) {
229- constantDims.d [i] = 1 ;
230- }
231- constantDims.d [diff - 1 ] =
232- bias.shape .d [0 ]; // Set C dimension to bias dim and other dimensions to 1 to enable broadcast
233- auto const_layer = ctx->net ->addConstant (constantDims, bias.data );
234- auto add_bias_layer =
235- ctx->net ->addElementWise (*tensorPtr, *const_layer->getOutput (0 ), nvinfer1::ElementWiseOperation::kSUM );
236-
237- new_layer = add_bias_layer;
262+ new_layer = add_bias_layer (ctx, tensorPtr, orig_dims, out_padding, bias);
238263 } else {
239264 new_layer = deconv;
240265 }
0 commit comments