senmaonk commited on
Commit
9d696c5
·
verified ·
1 Parent(s): 734c3ec

Upload 3 files

Browse files
basicsr/ops/dcn/src/deform_conv_cuda.cpp ADDED
@@ -0,0 +1,685 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // modify from
2
+ // https://github.com/chengdazhi/Deformable-Convolution-V2-PyTorch/blob/mmdetection/mmdet/ops/dcn/src/deform_conv_cuda.c
3
+
4
+ #include <torch/extension.h>
5
+ #include <ATen/DeviceGuard.h>
6
+
7
+ #include <cmath>
8
+ #include <vector>
9
+
10
+ void deformable_im2col(const at::Tensor data_im, const at::Tensor data_offset,
11
+ const int channels, const int height, const int width,
12
+ const int ksize_h, const int ksize_w, const int pad_h,
13
+ const int pad_w, const int stride_h, const int stride_w,
14
+ const int dilation_h, const int dilation_w,
15
+ const int parallel_imgs, const int deformable_group,
16
+ at::Tensor data_col);
17
+
18
+ void deformable_col2im(const at::Tensor data_col, const at::Tensor data_offset,
19
+ const int channels, const int height, const int width,
20
+ const int ksize_h, const int ksize_w, const int pad_h,
21
+ const int pad_w, const int stride_h, const int stride_w,
22
+ const int dilation_h, const int dilation_w,
23
+ const int parallel_imgs, const int deformable_group,
24
+ at::Tensor grad_im);
25
+
26
+ void deformable_col2im_coord(
27
+ const at::Tensor data_col, const at::Tensor data_im,
28
+ const at::Tensor data_offset, const int channels, const int height,
29
+ const int width, const int ksize_h, const int ksize_w, const int pad_h,
30
+ const int pad_w, const int stride_h, const int stride_w,
31
+ const int dilation_h, const int dilation_w, const int parallel_imgs,
32
+ const int deformable_group, at::Tensor grad_offset);
33
+
34
+ void modulated_deformable_im2col_cuda(
35
+ const at::Tensor data_im, const at::Tensor data_offset,
36
+ const at::Tensor data_mask, const int batch_size, const int channels,
37
+ const int height_im, const int width_im, const int height_col,
38
+ const int width_col, const int kernel_h, const int kenerl_w,
39
+ const int pad_h, const int pad_w, const int stride_h, const int stride_w,
40
+ const int dilation_h, const int dilation_w, const int deformable_group,
41
+ at::Tensor data_col);
42
+
43
+ void modulated_deformable_col2im_cuda(
44
+ const at::Tensor data_col, const at::Tensor data_offset,
45
+ const at::Tensor data_mask, const int batch_size, const int channels,
46
+ const int height_im, const int width_im, const int height_col,
47
+ const int width_col, const int kernel_h, const int kenerl_w,
48
+ const int pad_h, const int pad_w, const int stride_h, const int stride_w,
49
+ const int dilation_h, const int dilation_w, const int deformable_group,
50
+ at::Tensor grad_im);
51
+
52
+ void modulated_deformable_col2im_coord_cuda(
53
+ const at::Tensor data_col, const at::Tensor data_im,
54
+ const at::Tensor data_offset, const at::Tensor data_mask,
55
+ const int batch_size, const int channels, const int height_im,
56
+ const int width_im, const int height_col, const int width_col,
57
+ const int kernel_h, const int kenerl_w, const int pad_h, const int pad_w,
58
+ const int stride_h, const int stride_w, const int dilation_h,
59
+ const int dilation_w, const int deformable_group, at::Tensor grad_offset,
60
+ at::Tensor grad_mask);
61
+
62
+ void shape_check(at::Tensor input, at::Tensor offset, at::Tensor *gradOutput,
63
+ at::Tensor weight, int kH, int kW, int dH, int dW, int padH,
64
+ int padW, int dilationH, int dilationW, int group,
65
+ int deformable_group) {
66
+ TORCH_CHECK(weight.ndimension() == 4,
67
+ "4D weight tensor (nOutputPlane,nInputPlane,kH,kW) expected, "
68
+ "but got: %s",
69
+ weight.ndimension());
70
+
71
+ TORCH_CHECK(weight.is_contiguous(), "weight tensor has to be contiguous");
72
+
73
+ TORCH_CHECK(kW > 0 && kH > 0,
74
+ "kernel size should be greater than zero, but got kH: %d kW: %d", kH,
75
+ kW);
76
+
77
+ TORCH_CHECK((weight.size(2) == kH && weight.size(3) == kW),
78
+ "kernel size should be consistent with weight, ",
79
+ "but got kH: %d kW: %d weight.size(2): %d, weight.size(3): %d", kH,
80
+ kW, weight.size(2), weight.size(3));
81
+
82
+ TORCH_CHECK(dW > 0 && dH > 0,
83
+ "stride should be greater than zero, but got dH: %d dW: %d", dH, dW);
84
+
85
+ TORCH_CHECK(
86
+ dilationW > 0 && dilationH > 0,
87
+ "dilation should be greater than 0, but got dilationH: %d dilationW: %d",
88
+ dilationH, dilationW);
89
+
90
+ int ndim = input.ndimension();
91
+ int dimf = 0;
92
+ int dimh = 1;
93
+ int dimw = 2;
94
+
95
+ if (ndim == 4) {
96
+ dimf++;
97
+ dimh++;
98
+ dimw++;
99
+ }
100
+
101
+ TORCH_CHECK(ndim == 3 || ndim == 4, "3D or 4D input tensor expected but got: %s",
102
+ ndim);
103
+
104
+ long nInputPlane = weight.size(1) * group;
105
+ long inputHeight = input.size(dimh);
106
+ long inputWidth = input.size(dimw);
107
+ long nOutputPlane = weight.size(0);
108
+ long outputHeight =
109
+ (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1;
110
+ long outputWidth =
111
+ (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1;
112
+
113
+ TORCH_CHECK(nInputPlane % deformable_group == 0,
114
+ "input channels must divide deformable group size");
115
+
116
+ if (outputWidth < 1 || outputHeight < 1)
117
+ AT_ERROR(
118
+ "Given input size: (%ld x %ld x %ld). "
119
+ "Calculated output size: (%ld x %ld x %ld). Output size is too small",
120
+ nInputPlane, inputHeight, inputWidth, nOutputPlane, outputHeight,
121
+ outputWidth);
122
+
123
+ TORCH_CHECK(input.size(1) == nInputPlane,
124
+ "invalid number of input planes, expected: %d, but got: %d",
125
+ nInputPlane, input.size(1));
126
+
127
+ TORCH_CHECK((inputHeight >= kH && inputWidth >= kW),
128
+ "input image is smaller than kernel");
129
+
130
+ TORCH_CHECK((offset.size(2) == outputHeight && offset.size(3) == outputWidth),
131
+ "invalid spatial size of offset, expected height: %d width: %d, but "
132
+ "got height: %d width: %d",
133
+ outputHeight, outputWidth, offset.size(2), offset.size(3));
134
+
135
+ TORCH_CHECK((offset.size(1) == deformable_group * 2 * kH * kW),
136
+ "invalid number of channels of offset");
137
+
138
+ if (gradOutput != NULL) {
139
+ TORCH_CHECK(gradOutput->size(dimf) == nOutputPlane,
140
+ "invalid number of gradOutput planes, expected: %d, but got: %d",
141
+ nOutputPlane, gradOutput->size(dimf));
142
+
143
+ TORCH_CHECK((gradOutput->size(dimh) == outputHeight &&
144
+ gradOutput->size(dimw) == outputWidth),
145
+ "invalid size of gradOutput, expected height: %d width: %d , but "
146
+ "got height: %d width: %d",
147
+ outputHeight, outputWidth, gradOutput->size(dimh),
148
+ gradOutput->size(dimw));
149
+ }
150
+ }
151
+
152
+ int deform_conv_forward_cuda(at::Tensor input, at::Tensor weight,
153
+ at::Tensor offset, at::Tensor output,
154
+ at::Tensor columns, at::Tensor ones, int kW,
155
+ int kH, int dW, int dH, int padW, int padH,
156
+ int dilationW, int dilationH, int group,
157
+ int deformable_group, int im2col_step) {
158
+ // todo: resize columns to include im2col: done
159
+ // todo: add im2col_step as input
160
+ // todo: add new output buffer and transpose it to output (or directly
161
+ // transpose output) todo: possibly change data indexing because of
162
+ // parallel_imgs
163
+
164
+ shape_check(input, offset, NULL, weight, kH, kW, dH, dW, padH, padW,
165
+ dilationH, dilationW, group, deformable_group);
166
+ at::DeviceGuard guard(input.device());
167
+
168
+ input = input.contiguous();
169
+ offset = offset.contiguous();
170
+ weight = weight.contiguous();
171
+
172
+ int batch = 1;
173
+ if (input.ndimension() == 3) {
174
+ // Force batch
175
+ batch = 0;
176
+ input.unsqueeze_(0);
177
+ offset.unsqueeze_(0);
178
+ }
179
+
180
+ // todo: assert batchsize dividable by im2col_step
181
+
182
+ long batchSize = input.size(0);
183
+ long nInputPlane = input.size(1);
184
+ long inputHeight = input.size(2);
185
+ long inputWidth = input.size(3);
186
+
187
+ long nOutputPlane = weight.size(0);
188
+
189
+ long outputWidth =
190
+ (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1;
191
+ long outputHeight =
192
+ (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1;
193
+
194
+ TORCH_CHECK((offset.size(0) == batchSize), "invalid batch size of offset");
195
+
196
+ output = output.view({batchSize / im2col_step, im2col_step, nOutputPlane,
197
+ outputHeight, outputWidth});
198
+ columns = at::zeros(
199
+ {nInputPlane * kW * kH, im2col_step * outputHeight * outputWidth},
200
+ input.options());
201
+
202
+ if (ones.ndimension() != 2 ||
203
+ ones.size(0) * ones.size(1) < outputHeight * outputWidth) {
204
+ ones = at::ones({outputHeight, outputWidth}, input.options());
205
+ }
206
+
207
+ input = input.view({batchSize / im2col_step, im2col_step, nInputPlane,
208
+ inputHeight, inputWidth});
209
+ offset =
210
+ offset.view({batchSize / im2col_step, im2col_step,
211
+ deformable_group * 2 * kH * kW, outputHeight, outputWidth});
212
+
213
+ at::Tensor output_buffer =
214
+ at::zeros({batchSize / im2col_step, nOutputPlane,
215
+ im2col_step * outputHeight, outputWidth},
216
+ output.options());
217
+
218
+ output_buffer = output_buffer.view(
219
+ {output_buffer.size(0), group, output_buffer.size(1) / group,
220
+ output_buffer.size(2), output_buffer.size(3)});
221
+
222
+ for (int elt = 0; elt < batchSize / im2col_step; elt++) {
223
+ deformable_im2col(input[elt], offset[elt], nInputPlane, inputHeight,
224
+ inputWidth, kH, kW, padH, padW, dH, dW, dilationH,
225
+ dilationW, im2col_step, deformable_group, columns);
226
+
227
+ columns = columns.view({group, columns.size(0) / group, columns.size(1)});
228
+ weight = weight.view({group, weight.size(0) / group, weight.size(1),
229
+ weight.size(2), weight.size(3)});
230
+
231
+ for (int g = 0; g < group; g++) {
232
+ output_buffer[elt][g] = output_buffer[elt][g]
233
+ .flatten(1)
234
+ .addmm_(weight[g].flatten(1), columns[g])
235
+ .view_as(output_buffer[elt][g]);
236
+ }
237
+ }
238
+
239
+ output_buffer = output_buffer.view(
240
+ {output_buffer.size(0), output_buffer.size(1) * output_buffer.size(2),
241
+ output_buffer.size(3), output_buffer.size(4)});
242
+
243
+ output_buffer = output_buffer.view({batchSize / im2col_step, nOutputPlane,
244
+ im2col_step, outputHeight, outputWidth});
245
+ output_buffer.transpose_(1, 2);
246
+ output.copy_(output_buffer);
247
+ output = output.view({batchSize, nOutputPlane, outputHeight, outputWidth});
248
+
249
+ input = input.view({batchSize, nInputPlane, inputHeight, inputWidth});
250
+ offset = offset.view(
251
+ {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth});
252
+
253
+ if (batch == 0) {
254
+ output = output.view({nOutputPlane, outputHeight, outputWidth});
255
+ input = input.view({nInputPlane, inputHeight, inputWidth});
256
+ offset = offset.view({offset.size(1), offset.size(2), offset.size(3)});
257
+ }
258
+
259
+ return 1;
260
+ }
261
+
262
+ int deform_conv_backward_input_cuda(at::Tensor input, at::Tensor offset,
263
+ at::Tensor gradOutput, at::Tensor gradInput,
264
+ at::Tensor gradOffset, at::Tensor weight,
265
+ at::Tensor columns, int kW, int kH, int dW,
266
+ int dH, int padW, int padH, int dilationW,
267
+ int dilationH, int group,
268
+ int deformable_group, int im2col_step) {
269
+ shape_check(input, offset, &gradOutput, weight, kH, kW, dH, dW, padH, padW,
270
+ dilationH, dilationW, group, deformable_group);
271
+ at::DeviceGuard guard(input.device());
272
+
273
+ input = input.contiguous();
274
+ offset = offset.contiguous();
275
+ gradOutput = gradOutput.contiguous();
276
+ weight = weight.contiguous();
277
+
278
+ int batch = 1;
279
+
280
+ if (input.ndimension() == 3) {
281
+ // Force batch
282
+ batch = 0;
283
+ input = input.view({1, input.size(0), input.size(1), input.size(2)});
284
+ offset = offset.view({1, offset.size(0), offset.size(1), offset.size(2)});
285
+ gradOutput = gradOutput.view(
286
+ {1, gradOutput.size(0), gradOutput.size(1), gradOutput.size(2)});
287
+ }
288
+
289
+ long batchSize = input.size(0);
290
+ long nInputPlane = input.size(1);
291
+ long inputHeight = input.size(2);
292
+ long inputWidth = input.size(3);
293
+
294
+ long nOutputPlane = weight.size(0);
295
+
296
+ long outputWidth =
297
+ (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1;
298
+ long outputHeight =
299
+ (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1;
300
+
301
+ TORCH_CHECK((offset.size(0) == batchSize), 3, "invalid batch size of offset");
302
+ gradInput = gradInput.view({batchSize, nInputPlane, inputHeight, inputWidth});
303
+ columns = at::zeros(
304
+ {nInputPlane * kW * kH, im2col_step * outputHeight * outputWidth},
305
+ input.options());
306
+
307
+ // change order of grad output
308
+ gradOutput = gradOutput.view({batchSize / im2col_step, im2col_step,
309
+ nOutputPlane, outputHeight, outputWidth});
310
+ gradOutput.transpose_(1, 2);
311
+
312
+ gradInput = gradInput.view({batchSize / im2col_step, im2col_step, nInputPlane,
313
+ inputHeight, inputWidth});
314
+ input = input.view({batchSize / im2col_step, im2col_step, nInputPlane,
315
+ inputHeight, inputWidth});
316
+ gradOffset = gradOffset.view({batchSize / im2col_step, im2col_step,
317
+ deformable_group * 2 * kH * kW, outputHeight,
318
+ outputWidth});
319
+ offset =
320
+ offset.view({batchSize / im2col_step, im2col_step,
321
+ deformable_group * 2 * kH * kW, outputHeight, outputWidth});
322
+
323
+ for (int elt = 0; elt < batchSize / im2col_step; elt++) {
324
+ // divide into groups
325
+ columns = columns.view({group, columns.size(0) / group, columns.size(1)});
326
+ weight = weight.view({group, weight.size(0) / group, weight.size(1),
327
+ weight.size(2), weight.size(3)});
328
+ gradOutput = gradOutput.view(
329
+ {gradOutput.size(0), group, gradOutput.size(1) / group,
330
+ gradOutput.size(2), gradOutput.size(3), gradOutput.size(4)});
331
+
332
+ for (int g = 0; g < group; g++) {
333
+ columns[g] = columns[g].addmm_(weight[g].flatten(1).transpose(0, 1),
334
+ gradOutput[elt][g].flatten(1), 0.0f, 1.0f);
335
+ }
336
+
337
+ columns =
338
+ columns.view({columns.size(0) * columns.size(1), columns.size(2)});
339
+ gradOutput = gradOutput.view(
340
+ {gradOutput.size(0), gradOutput.size(1) * gradOutput.size(2),
341
+ gradOutput.size(3), gradOutput.size(4), gradOutput.size(5)});
342
+
343
+ deformable_col2im_coord(columns, input[elt], offset[elt], nInputPlane,
344
+ inputHeight, inputWidth, kH, kW, padH, padW, dH, dW,
345
+ dilationH, dilationW, im2col_step, deformable_group,
346
+ gradOffset[elt]);
347
+
348
+ deformable_col2im(columns, offset[elt], nInputPlane, inputHeight,
349
+ inputWidth, kH, kW, padH, padW, dH, dW, dilationH,
350
+ dilationW, im2col_step, deformable_group, gradInput[elt]);
351
+ }
352
+
353
+ gradOutput.transpose_(1, 2);
354
+ gradOutput =
355
+ gradOutput.view({batchSize, nOutputPlane, outputHeight, outputWidth});
356
+
357
+ gradInput = gradInput.view({batchSize, nInputPlane, inputHeight, inputWidth});
358
+ input = input.view({batchSize, nInputPlane, inputHeight, inputWidth});
359
+ gradOffset = gradOffset.view(
360
+ {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth});
361
+ offset = offset.view(
362
+ {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth});
363
+
364
+ if (batch == 0) {
365
+ gradOutput = gradOutput.view({nOutputPlane, outputHeight, outputWidth});
366
+ input = input.view({nInputPlane, inputHeight, inputWidth});
367
+ gradInput = gradInput.view({nInputPlane, inputHeight, inputWidth});
368
+ offset = offset.view({offset.size(1), offset.size(2), offset.size(3)});
369
+ gradOffset =
370
+ gradOffset.view({offset.size(1), offset.size(2), offset.size(3)});
371
+ }
372
+
373
+ return 1;
374
+ }
375
+
376
+ int deform_conv_backward_parameters_cuda(
377
+ at::Tensor input, at::Tensor offset, at::Tensor gradOutput,
378
+ at::Tensor gradWeight, // at::Tensor gradBias,
379
+ at::Tensor columns, at::Tensor ones, int kW, int kH, int dW, int dH,
380
+ int padW, int padH, int dilationW, int dilationH, int group,
381
+ int deformable_group, float scale, int im2col_step) {
382
+ // todo: transpose and reshape outGrad
383
+ // todo: reshape columns
384
+ // todo: add im2col_step as input
385
+
386
+ shape_check(input, offset, &gradOutput, gradWeight, kH, kW, dH, dW, padH,
387
+ padW, dilationH, dilationW, group, deformable_group);
388
+ at::DeviceGuard guard(input.device());
389
+
390
+ input = input.contiguous();
391
+ offset = offset.contiguous();
392
+ gradOutput = gradOutput.contiguous();
393
+
394
+ int batch = 1;
395
+
396
+ if (input.ndimension() == 3) {
397
+ // Force batch
398
+ batch = 0;
399
+ input = input.view(
400
+ at::IntList({1, input.size(0), input.size(1), input.size(2)}));
401
+ gradOutput = gradOutput.view(
402
+ {1, gradOutput.size(0), gradOutput.size(1), gradOutput.size(2)});
403
+ }
404
+
405
+ long batchSize = input.size(0);
406
+ long nInputPlane = input.size(1);
407
+ long inputHeight = input.size(2);
408
+ long inputWidth = input.size(3);
409
+
410
+ long nOutputPlane = gradWeight.size(0);
411
+
412
+ long outputWidth =
413
+ (inputWidth + 2 * padW - (dilationW * (kW - 1) + 1)) / dW + 1;
414
+ long outputHeight =
415
+ (inputHeight + 2 * padH - (dilationH * (kH - 1) + 1)) / dH + 1;
416
+
417
+ TORCH_CHECK((offset.size(0) == batchSize), "invalid batch size of offset");
418
+
419
+ columns = at::zeros(
420
+ {nInputPlane * kW * kH, im2col_step * outputHeight * outputWidth},
421
+ input.options());
422
+
423
+ gradOutput = gradOutput.view({batchSize / im2col_step, im2col_step,
424
+ nOutputPlane, outputHeight, outputWidth});
425
+ gradOutput.transpose_(1, 2);
426
+
427
+ at::Tensor gradOutputBuffer = at::zeros_like(gradOutput);
428
+ gradOutputBuffer =
429
+ gradOutputBuffer.view({batchSize / im2col_step, nOutputPlane, im2col_step,
430
+ outputHeight, outputWidth});
431
+ gradOutputBuffer.copy_(gradOutput);
432
+ gradOutputBuffer =
433
+ gradOutputBuffer.view({batchSize / im2col_step, nOutputPlane,
434
+ im2col_step * outputHeight, outputWidth});
435
+
436
+ gradOutput.transpose_(1, 2);
437
+ gradOutput =
438
+ gradOutput.view({batchSize, nOutputPlane, outputHeight, outputWidth});
439
+
440
+ input = input.view({batchSize / im2col_step, im2col_step, nInputPlane,
441
+ inputHeight, inputWidth});
442
+ offset =
443
+ offset.view({batchSize / im2col_step, im2col_step,
444
+ deformable_group * 2 * kH * kW, outputHeight, outputWidth});
445
+
446
+ for (int elt = 0; elt < batchSize / im2col_step; elt++) {
447
+ deformable_im2col(input[elt], offset[elt], nInputPlane, inputHeight,
448
+ inputWidth, kH, kW, padH, padW, dH, dW, dilationH,
449
+ dilationW, im2col_step, deformable_group, columns);
450
+
451
+ // divide into group
452
+ gradOutputBuffer = gradOutputBuffer.view(
453
+ {gradOutputBuffer.size(0), group, gradOutputBuffer.size(1) / group,
454
+ gradOutputBuffer.size(2), gradOutputBuffer.size(3)});
455
+ columns = columns.view({group, columns.size(0) / group, columns.size(1)});
456
+ gradWeight =
457
+ gradWeight.view({group, gradWeight.size(0) / group, gradWeight.size(1),
458
+ gradWeight.size(2), gradWeight.size(3)});
459
+
460
+ for (int g = 0; g < group; g++) {
461
+ gradWeight[g] = gradWeight[g]
462
+ .flatten(1)
463
+ .addmm_(gradOutputBuffer[elt][g].flatten(1),
464
+ columns[g].transpose(1, 0), 1.0, scale)
465
+ .view_as(gradWeight[g]);
466
+ }
467
+ gradOutputBuffer = gradOutputBuffer.view(
468
+ {gradOutputBuffer.size(0),
469
+ gradOutputBuffer.size(1) * gradOutputBuffer.size(2),
470
+ gradOutputBuffer.size(3), gradOutputBuffer.size(4)});
471
+ columns =
472
+ columns.view({columns.size(0) * columns.size(1), columns.size(2)});
473
+ gradWeight = gradWeight.view({gradWeight.size(0) * gradWeight.size(1),
474
+ gradWeight.size(2), gradWeight.size(3),
475
+ gradWeight.size(4)});
476
+ }
477
+
478
+ input = input.view({batchSize, nInputPlane, inputHeight, inputWidth});
479
+ offset = offset.view(
480
+ {batchSize, deformable_group * 2 * kH * kW, outputHeight, outputWidth});
481
+
482
+ if (batch == 0) {
483
+ gradOutput = gradOutput.view({nOutputPlane, outputHeight, outputWidth});
484
+ input = input.view({nInputPlane, inputHeight, inputWidth});
485
+ }
486
+
487
+ return 1;
488
+ }
489
+
490
+ void modulated_deform_conv_cuda_forward(
491
+ at::Tensor input, at::Tensor weight, at::Tensor bias, at::Tensor ones,
492
+ at::Tensor offset, at::Tensor mask, at::Tensor output, at::Tensor columns,
493
+ int kernel_h, int kernel_w, const int stride_h, const int stride_w,
494
+ const int pad_h, const int pad_w, const int dilation_h,
495
+ const int dilation_w, const int group, const int deformable_group,
496
+ const bool with_bias) {
497
+ TORCH_CHECK(input.is_contiguous(), "input tensor has to be contiguous");
498
+ TORCH_CHECK(weight.is_contiguous(), "weight tensor has to be contiguous");
499
+ at::DeviceGuard guard(input.device());
500
+
501
+ const int batch = input.size(0);
502
+ const int channels = input.size(1);
503
+ const int height = input.size(2);
504
+ const int width = input.size(3);
505
+
506
+ const int channels_out = weight.size(0);
507
+ const int channels_kernel = weight.size(1);
508
+ const int kernel_h_ = weight.size(2);
509
+ const int kernel_w_ = weight.size(3);
510
+
511
+ if (kernel_h_ != kernel_h || kernel_w_ != kernel_w)
512
+ AT_ERROR("Input shape and kernel shape wont match: (%d x %d vs %d x %d).",
513
+ kernel_h_, kernel_w, kernel_h_, kernel_w_);
514
+ if (channels != channels_kernel * group)
515
+ AT_ERROR("Input shape and kernel channels wont match: (%d vs %d).",
516
+ channels, channels_kernel * group);
517
+
518
+ const int height_out =
519
+ (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
520
+ const int width_out =
521
+ (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
522
+
523
+ if (ones.ndimension() != 2 ||
524
+ ones.size(0) * ones.size(1) < height_out * width_out) {
525
+ // Resize plane and fill with ones...
526
+ ones = at::ones({height_out, width_out}, input.options());
527
+ }
528
+
529
+ // resize output
530
+ output = output.view({batch, channels_out, height_out, width_out}).zero_();
531
+ // resize temporary columns
532
+ columns =
533
+ at::zeros({channels * kernel_h * kernel_w, 1 * height_out * width_out},
534
+ input.options());
535
+
536
+ output = output.view({output.size(0), group, output.size(1) / group,
537
+ output.size(2), output.size(3)});
538
+
539
+ for (int b = 0; b < batch; b++) {
540
+ modulated_deformable_im2col_cuda(
541
+ input[b], offset[b], mask[b], 1, channels, height, width, height_out,
542
+ width_out, kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
543
+ dilation_h, dilation_w, deformable_group, columns);
544
+
545
+ // divide into group
546
+ weight = weight.view({group, weight.size(0) / group, weight.size(1),
547
+ weight.size(2), weight.size(3)});
548
+ columns = columns.view({group, columns.size(0) / group, columns.size(1)});
549
+
550
+ for (int g = 0; g < group; g++) {
551
+ output[b][g] = output[b][g]
552
+ .flatten(1)
553
+ .addmm_(weight[g].flatten(1), columns[g])
554
+ .view_as(output[b][g]);
555
+ }
556
+
557
+ weight = weight.view({weight.size(0) * weight.size(1), weight.size(2),
558
+ weight.size(3), weight.size(4)});
559
+ columns =
560
+ columns.view({columns.size(0) * columns.size(1), columns.size(2)});
561
+ }
562
+
563
+ output = output.view({output.size(0), output.size(1) * output.size(2),
564
+ output.size(3), output.size(4)});
565
+
566
+ if (with_bias) {
567
+ output += bias.view({1, bias.size(0), 1, 1});
568
+ }
569
+ }
570
+
571
+ void modulated_deform_conv_cuda_backward(
572
+ at::Tensor input, at::Tensor weight, at::Tensor bias, at::Tensor ones,
573
+ at::Tensor offset, at::Tensor mask, at::Tensor columns,
574
+ at::Tensor grad_input, at::Tensor grad_weight, at::Tensor grad_bias,
575
+ at::Tensor grad_offset, at::Tensor grad_mask, at::Tensor grad_output,
576
+ int kernel_h, int kernel_w, int stride_h, int stride_w, int pad_h,
577
+ int pad_w, int dilation_h, int dilation_w, int group, int deformable_group,
578
+ const bool with_bias) {
579
+ TORCH_CHECK(input.is_contiguous(), "input tensor has to be contiguous");
580
+ TORCH_CHECK(weight.is_contiguous(), "weight tensor has to be contiguous");
581
+ at::DeviceGuard guard(input.device());
582
+
583
+ const int batch = input.size(0);
584
+ const int channels = input.size(1);
585
+ const int height = input.size(2);
586
+ const int width = input.size(3);
587
+
588
+ const int channels_kernel = weight.size(1);
589
+ const int kernel_h_ = weight.size(2);
590
+ const int kernel_w_ = weight.size(3);
591
+ if (kernel_h_ != kernel_h || kernel_w_ != kernel_w)
592
+ AT_ERROR("Input shape and kernel shape wont match: (%d x %d vs %d x %d).",
593
+ kernel_h_, kernel_w, kernel_h_, kernel_w_);
594
+ if (channels != channels_kernel * group)
595
+ AT_ERROR("Input shape and kernel channels wont match: (%d vs %d).",
596
+ channels, channels_kernel * group);
597
+
598
+ const int height_out =
599
+ (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
600
+ const int width_out =
601
+ (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
602
+
603
+ if (ones.ndimension() != 2 ||
604
+ ones.size(0) * ones.size(1) < height_out * width_out) {
605
+ // Resize plane and fill with ones...
606
+ ones = at::ones({height_out, width_out}, input.options());
607
+ }
608
+
609
+ grad_input = grad_input.view({batch, channels, height, width});
610
+ columns = at::zeros({channels * kernel_h * kernel_w, height_out * width_out},
611
+ input.options());
612
+
613
+ grad_output =
614
+ grad_output.view({grad_output.size(0), group, grad_output.size(1) / group,
615
+ grad_output.size(2), grad_output.size(3)});
616
+
617
+ for (int b = 0; b < batch; b++) {
618
+ // divide int group
619
+ columns = columns.view({group, columns.size(0) / group, columns.size(1)});
620
+ weight = weight.view({group, weight.size(0) / group, weight.size(1),
621
+ weight.size(2), weight.size(3)});
622
+
623
+ for (int g = 0; g < group; g++) {
624
+ columns[g].addmm_(weight[g].flatten(1).transpose(0, 1),
625
+ grad_output[b][g].flatten(1), 0.0f, 1.0f);
626
+ }
627
+
628
+ columns =
629
+ columns.view({columns.size(0) * columns.size(1), columns.size(2)});
630
+ weight = weight.view({weight.size(0) * weight.size(1), weight.size(2),
631
+ weight.size(3), weight.size(4)});
632
+
633
+ // gradient w.r.t. input coordinate data
634
+ modulated_deformable_col2im_coord_cuda(
635
+ columns, input[b], offset[b], mask[b], 1, channels, height, width,
636
+ height_out, width_out, kernel_h, kernel_w, pad_h, pad_w, stride_h,
637
+ stride_w, dilation_h, dilation_w, deformable_group, grad_offset[b],
638
+ grad_mask[b]);
639
+ // gradient w.r.t. input data
640
+ modulated_deformable_col2im_cuda(
641
+ columns, offset[b], mask[b], 1, channels, height, width, height_out,
642
+ width_out, kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
643
+ dilation_h, dilation_w, deformable_group, grad_input[b]);
644
+
645
+ // gradient w.r.t. weight, dWeight should accumulate across the batch and
646
+ // group
647
+ modulated_deformable_im2col_cuda(
648
+ input[b], offset[b], mask[b], 1, channels, height, width, height_out,
649
+ width_out, kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
650
+ dilation_h, dilation_w, deformable_group, columns);
651
+
652
+ columns = columns.view({group, columns.size(0) / group, columns.size(1)});
653
+ grad_weight = grad_weight.view({group, grad_weight.size(0) / group,
654
+ grad_weight.size(1), grad_weight.size(2),
655
+ grad_weight.size(3)});
656
+ if (with_bias)
657
+ grad_bias = grad_bias.view({group, grad_bias.size(0) / group});
658
+
659
+ for (int g = 0; g < group; g++) {
660
+ grad_weight[g] =
661
+ grad_weight[g]
662
+ .flatten(1)
663
+ .addmm_(grad_output[b][g].flatten(1), columns[g].transpose(0, 1))
664
+ .view_as(grad_weight[g]);
665
+ if (with_bias) {
666
+ grad_bias[g] =
667
+ grad_bias[g]
668
+ .view({-1, 1})
669
+ .addmm_(grad_output[b][g].flatten(1), ones.view({-1, 1}))
670
+ .view(-1);
671
+ }
672
+ }
673
+
674
+ columns =
675
+ columns.view({columns.size(0) * columns.size(1), columns.size(2)});
676
+ grad_weight = grad_weight.view({grad_weight.size(0) * grad_weight.size(1),
677
+ grad_weight.size(2), grad_weight.size(3),
678
+ grad_weight.size(4)});
679
+ if (with_bias)
680
+ grad_bias = grad_bias.view({grad_bias.size(0) * grad_bias.size(1)});
681
+ }
682
+ grad_output = grad_output.view({grad_output.size(0) * grad_output.size(1),
683
+ grad_output.size(2), grad_output.size(3),
684
+ grad_output.size(4)});
685
+ }
basicsr/ops/dcn/src/deform_conv_cuda_kernel.cu ADDED
@@ -0,0 +1,867 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ ******************* BEGIN Caffe Copyright Notice and Disclaimer ****************
3
+ *
4
+ * COPYRIGHT
5
+ *
6
+ * All contributions by the University of California:
7
+ * Copyright (c) 2014-2017 The Regents of the University of California (Regents)
8
+ * All rights reserved.
9
+ *
10
+ * All other contributions:
11
+ * Copyright (c) 2014-2017, the respective contributors
12
+ * All rights reserved.
13
+ *
14
+ * Caffe uses a shared copyright model: each contributor holds copyright over
15
+ * their contributions to Caffe. The project versioning records all such
16
+ * contribution and copyright details. If a contributor wants to further mark
17
+ * their specific copyright on a particular contribution, they should indicate
18
+ * their copyright solely in the commit message of the change when it is
19
+ * committed.
20
+ *
21
+ * LICENSE
22
+ *
23
+ * Redistribution and use in source and binary forms, with or without
24
+ * modification, are permitted provided that the following conditions are met:
25
+ *
26
+ * 1. Redistributions of source code must retain the above copyright notice, this
27
+ * list of conditions and the following disclaimer.
28
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
29
+ * this list of conditions and the following disclaimer in the documentation
30
+ * and/or other materials provided with the distribution.
31
+ *
32
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
36
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42
+ *
43
+ * CONTRIBUTION AGREEMENT
44
+ *
45
+ * By contributing to the BVLC/caffe repository through pull-request, comment,
46
+ * or otherwise, the contributor releases their content to the
47
+ * license and copyright terms herein.
48
+ *
49
+ ***************** END Caffe Copyright Notice and Disclaimer ********************
50
+ *
51
+ * Copyright (c) 2018 Microsoft
52
+ * Licensed under The MIT License [see LICENSE for details]
53
+ * \file modulated_deformable_im2col.cuh
54
+ * \brief Function definitions of converting an image to
55
+ * column matrix based on kernel, padding, dilation, and offset.
56
+ * These functions are mainly used in deformable convolution operators.
57
+ * \ref: https://arxiv.org/abs/1703.06211
58
+ * \author Yuwen Xiong, Haozhi Qi, Jifeng Dai, Xizhou Zhu, Han Hu, Dazhi Cheng
59
+ */
60
+
61
+ // modified from https://github.com/chengdazhi/Deformable-Convolution-V2-PyTorch/blob/mmdetection/mmdet/ops/dcn/src/deform_conv_cuda_kernel.cu
62
+
63
+ #include <ATen/ATen.h>
64
+ #include <ATen/cuda/CUDAContext.h>
65
+ #include <THC/THCAtomics.cuh>
66
+ #include <stdio.h>
67
+ #include <math.h>
68
+ #include <float.h>
69
+
70
+ using namespace at;
71
+
72
+ #define CUDA_KERNEL_LOOP(i, n) \
73
+ for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < (n); \
74
+ i += blockDim.x * gridDim.x)
75
+
76
+ const int CUDA_NUM_THREADS = 1024;
77
+ const int kMaxGridNum = 65535;
78
+
79
+ inline int GET_BLOCKS(const int N)
80
+ {
81
+ return std::min(kMaxGridNum, (N + CUDA_NUM_THREADS - 1) / CUDA_NUM_THREADS);
82
+ }
83
+
84
+ template <typename scalar_t>
85
+ __device__ scalar_t deformable_im2col_bilinear(const scalar_t *bottom_data, const int data_width,
86
+ const int height, const int width, scalar_t h, scalar_t w)
87
+ {
88
+
89
+ int h_low = floor(h);
90
+ int w_low = floor(w);
91
+ int h_high = h_low + 1;
92
+ int w_high = w_low + 1;
93
+
94
+ scalar_t lh = h - h_low;
95
+ scalar_t lw = w - w_low;
96
+ scalar_t hh = 1 - lh, hw = 1 - lw;
97
+
98
+ scalar_t v1 = 0;
99
+ if (h_low >= 0 && w_low >= 0)
100
+ v1 = bottom_data[h_low * data_width + w_low];
101
+ scalar_t v2 = 0;
102
+ if (h_low >= 0 && w_high <= width - 1)
103
+ v2 = bottom_data[h_low * data_width + w_high];
104
+ scalar_t v3 = 0;
105
+ if (h_high <= height - 1 && w_low >= 0)
106
+ v3 = bottom_data[h_high * data_width + w_low];
107
+ scalar_t v4 = 0;
108
+ if (h_high <= height - 1 && w_high <= width - 1)
109
+ v4 = bottom_data[h_high * data_width + w_high];
110
+
111
+ scalar_t w1 = hh * hw, w2 = hh * lw, w3 = lh * hw, w4 = lh * lw;
112
+
113
+ scalar_t val = (w1 * v1 + w2 * v2 + w3 * v3 + w4 * v4);
114
+ return val;
115
+ }
116
+
117
+ template <typename scalar_t>
118
+ __device__ scalar_t get_gradient_weight(scalar_t argmax_h, scalar_t argmax_w,
119
+ const int h, const int w, const int height, const int width)
120
+ {
121
+
122
+ if (argmax_h <= -1 || argmax_h >= height || argmax_w <= -1 || argmax_w >= width)
123
+ {
124
+ //empty
125
+ return 0;
126
+ }
127
+
128
+ int argmax_h_low = floor(argmax_h);
129
+ int argmax_w_low = floor(argmax_w);
130
+ int argmax_h_high = argmax_h_low + 1;
131
+ int argmax_w_high = argmax_w_low + 1;
132
+
133
+ scalar_t weight = 0;
134
+ if (h == argmax_h_low && w == argmax_w_low)
135
+ weight = (h + 1 - argmax_h) * (w + 1 - argmax_w);
136
+ if (h == argmax_h_low && w == argmax_w_high)
137
+ weight = (h + 1 - argmax_h) * (argmax_w + 1 - w);
138
+ if (h == argmax_h_high && w == argmax_w_low)
139
+ weight = (argmax_h + 1 - h) * (w + 1 - argmax_w);
140
+ if (h == argmax_h_high && w == argmax_w_high)
141
+ weight = (argmax_h + 1 - h) * (argmax_w + 1 - w);
142
+ return weight;
143
+ }
144
+
145
+ template <typename scalar_t>
146
+ __device__ scalar_t get_coordinate_weight(scalar_t argmax_h, scalar_t argmax_w,
147
+ const int height, const int width, const scalar_t *im_data,
148
+ const int data_width, const int bp_dir)
149
+ {
150
+
151
+ if (argmax_h <= -1 || argmax_h >= height || argmax_w <= -1 || argmax_w >= width)
152
+ {
153
+ //empty
154
+ return 0;
155
+ }
156
+
157
+ int argmax_h_low = floor(argmax_h);
158
+ int argmax_w_low = floor(argmax_w);
159
+ int argmax_h_high = argmax_h_low + 1;
160
+ int argmax_w_high = argmax_w_low + 1;
161
+
162
+ scalar_t weight = 0;
163
+
164
+ if (bp_dir == 0)
165
+ {
166
+ if (argmax_h_low >= 0 && argmax_w_low >= 0)
167
+ weight += -1 * (argmax_w_low + 1 - argmax_w) * im_data[argmax_h_low * data_width + argmax_w_low];
168
+ if (argmax_h_low >= 0 && argmax_w_high <= width - 1)
169
+ weight += -1 * (argmax_w - argmax_w_low) * im_data[argmax_h_low * data_width + argmax_w_high];
170
+ if (argmax_h_high <= height - 1 && argmax_w_low >= 0)
171
+ weight += (argmax_w_low + 1 - argmax_w) * im_data[argmax_h_high * data_width + argmax_w_low];
172
+ if (argmax_h_high <= height - 1 && argmax_w_high <= width - 1)
173
+ weight += (argmax_w - argmax_w_low) * im_data[argmax_h_high * data_width + argmax_w_high];
174
+ }
175
+ else if (bp_dir == 1)
176
+ {
177
+ if (argmax_h_low >= 0 && argmax_w_low >= 0)
178
+ weight += -1 * (argmax_h_low + 1 - argmax_h) * im_data[argmax_h_low * data_width + argmax_w_low];
179
+ if (argmax_h_low >= 0 && argmax_w_high <= width - 1)
180
+ weight += (argmax_h_low + 1 - argmax_h) * im_data[argmax_h_low * data_width + argmax_w_high];
181
+ if (argmax_h_high <= height - 1 && argmax_w_low >= 0)
182
+ weight += -1 * (argmax_h - argmax_h_low) * im_data[argmax_h_high * data_width + argmax_w_low];
183
+ if (argmax_h_high <= height - 1 && argmax_w_high <= width - 1)
184
+ weight += (argmax_h - argmax_h_low) * im_data[argmax_h_high * data_width + argmax_w_high];
185
+ }
186
+
187
+ return weight;
188
+ }
189
+
190
+ template <typename scalar_t>
191
+ __global__ void deformable_im2col_gpu_kernel(const int n, const scalar_t *data_im, const scalar_t *data_offset,
192
+ const int height, const int width, const int kernel_h, const int kernel_w,
193
+ const int pad_h, const int pad_w, const int stride_h, const int stride_w,
194
+ const int dilation_h, const int dilation_w, const int channel_per_deformable_group,
195
+ const int batch_size, const int num_channels, const int deformable_group,
196
+ const int height_col, const int width_col,
197
+ scalar_t *data_col)
198
+ {
199
+ CUDA_KERNEL_LOOP(index, n)
200
+ {
201
+ // index index of output matrix
202
+ const int w_col = index % width_col;
203
+ const int h_col = (index / width_col) % height_col;
204
+ const int b_col = (index / width_col / height_col) % batch_size;
205
+ const int c_im = (index / width_col / height_col) / batch_size;
206
+ const int c_col = c_im * kernel_h * kernel_w;
207
+
208
+ // compute deformable group index
209
+ const int deformable_group_index = c_im / channel_per_deformable_group;
210
+
211
+ const int h_in = h_col * stride_h - pad_h;
212
+ const int w_in = w_col * stride_w - pad_w;
213
+ scalar_t *data_col_ptr = data_col + ((c_col * batch_size + b_col) * height_col + h_col) * width_col + w_col;
214
+ //const scalar_t* data_im_ptr = data_im + ((b_col * num_channels + c_im) * height + h_in) * width + w_in;
215
+ const scalar_t *data_im_ptr = data_im + (b_col * num_channels + c_im) * height * width;
216
+ const scalar_t *data_offset_ptr = data_offset + (b_col * deformable_group + deformable_group_index) * 2 * kernel_h * kernel_w * height_col * width_col;
217
+
218
+ for (int i = 0; i < kernel_h; ++i)
219
+ {
220
+ for (int j = 0; j < kernel_w; ++j)
221
+ {
222
+ const int data_offset_h_ptr = ((2 * (i * kernel_w + j)) * height_col + h_col) * width_col + w_col;
223
+ const int data_offset_w_ptr = ((2 * (i * kernel_w + j) + 1) * height_col + h_col) * width_col + w_col;
224
+ const scalar_t offset_h = data_offset_ptr[data_offset_h_ptr];
225
+ const scalar_t offset_w = data_offset_ptr[data_offset_w_ptr];
226
+ scalar_t val = static_cast<scalar_t>(0);
227
+ const scalar_t h_im = h_in + i * dilation_h + offset_h;
228
+ const scalar_t w_im = w_in + j * dilation_w + offset_w;
229
+ if (h_im > -1 && w_im > -1 && h_im < height && w_im < width)
230
+ {
231
+ //const scalar_t map_h = i * dilation_h + offset_h;
232
+ //const scalar_t map_w = j * dilation_w + offset_w;
233
+ //const int cur_height = height - h_in;
234
+ //const int cur_width = width - w_in;
235
+ //val = deformable_im2col_bilinear(data_im_ptr, width, cur_height, cur_width, map_h, map_w);
236
+ val = deformable_im2col_bilinear(data_im_ptr, width, height, width, h_im, w_im);
237
+ }
238
+ *data_col_ptr = val;
239
+ data_col_ptr += batch_size * height_col * width_col;
240
+ }
241
+ }
242
+ }
243
+ }
244
+
245
+ void deformable_im2col(
246
+ const at::Tensor data_im, const at::Tensor data_offset, const int channels,
247
+ const int height, const int width, const int ksize_h, const int ksize_w,
248
+ const int pad_h, const int pad_w, const int stride_h, const int stride_w,
249
+ const int dilation_h, const int dilation_w, const int parallel_imgs,
250
+ const int deformable_group, at::Tensor data_col)
251
+ {
252
+ // num_axes should be smaller than block size
253
+ // todo: check parallel_imgs is correctly passed in
254
+ int height_col = (height + 2 * pad_h - (dilation_h * (ksize_h - 1) + 1)) / stride_h + 1;
255
+ int width_col = (width + 2 * pad_w - (dilation_w * (ksize_w - 1) + 1)) / stride_w + 1;
256
+ int num_kernels = channels * height_col * width_col * parallel_imgs;
257
+ int channel_per_deformable_group = channels / deformable_group;
258
+
259
+ AT_DISPATCH_FLOATING_TYPES_AND_HALF(
260
+ data_im.scalar_type(), "deformable_im2col_gpu", ([&] {
261
+ const scalar_t *data_im_ = data_im.data_ptr<scalar_t>();
262
+ const scalar_t *data_offset_ = data_offset.data_ptr<scalar_t>();
263
+ scalar_t *data_col_ = data_col.data_ptr<scalar_t>();
264
+
265
+ deformable_im2col_gpu_kernel<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS, 0, at::cuda::getCurrentCUDAStream()>>>(
266
+ num_kernels, data_im_, data_offset_, height, width, ksize_h, ksize_w,
267
+ pad_h, pad_w, stride_h, stride_w, dilation_h, dilation_w,
268
+ channel_per_deformable_group, parallel_imgs, channels, deformable_group,
269
+ height_col, width_col, data_col_);
270
+ }));
271
+
272
+ cudaError_t err = cudaGetLastError();
273
+ if (err != cudaSuccess)
274
+ {
275
+ printf("error in deformable_im2col: %s\n", cudaGetErrorString(err));
276
+ }
277
+ }
278
+
279
+ template <typename scalar_t>
280
+ __global__ void deformable_col2im_gpu_kernel(
281
+ const int n, const scalar_t *data_col, const scalar_t *data_offset,
282
+ const int channels, const int height, const int width,
283
+ const int kernel_h, const int kernel_w,
284
+ const int pad_h, const int pad_w,
285
+ const int stride_h, const int stride_w,
286
+ const int dilation_h, const int dilation_w,
287
+ const int channel_per_deformable_group,
288
+ const int batch_size, const int deformable_group,
289
+ const int height_col, const int width_col,
290
+ scalar_t *grad_im)
291
+ {
292
+ CUDA_KERNEL_LOOP(index, n)
293
+ {
294
+ const int j = (index / width_col / height_col / batch_size) % kernel_w;
295
+ const int i = (index / width_col / height_col / batch_size / kernel_w) % kernel_h;
296
+ const int c = index / width_col / height_col / batch_size / kernel_w / kernel_h;
297
+ // compute the start and end of the output
298
+
299
+ const int deformable_group_index = c / channel_per_deformable_group;
300
+
301
+ int w_out = index % width_col;
302
+ int h_out = (index / width_col) % height_col;
303
+ int b = (index / width_col / height_col) % batch_size;
304
+ int w_in = w_out * stride_w - pad_w;
305
+ int h_in = h_out * stride_h - pad_h;
306
+
307
+ const scalar_t *data_offset_ptr = data_offset + (b * deformable_group + deformable_group_index) *
308
+ 2 * kernel_h * kernel_w * height_col * width_col;
309
+ const int data_offset_h_ptr = ((2 * (i * kernel_w + j)) * height_col + h_out) * width_col + w_out;
310
+ const int data_offset_w_ptr = ((2 * (i * kernel_w + j) + 1) * height_col + h_out) * width_col + w_out;
311
+ const scalar_t offset_h = data_offset_ptr[data_offset_h_ptr];
312
+ const scalar_t offset_w = data_offset_ptr[data_offset_w_ptr];
313
+ const scalar_t cur_inv_h_data = h_in + i * dilation_h + offset_h;
314
+ const scalar_t cur_inv_w_data = w_in + j * dilation_w + offset_w;
315
+
316
+ const scalar_t cur_top_grad = data_col[index];
317
+ const int cur_h = (int)cur_inv_h_data;
318
+ const int cur_w = (int)cur_inv_w_data;
319
+ for (int dy = -2; dy <= 2; dy++)
320
+ {
321
+ for (int dx = -2; dx <= 2; dx++)
322
+ {
323
+ if (cur_h + dy >= 0 && cur_h + dy < height &&
324
+ cur_w + dx >= 0 && cur_w + dx < width &&
325
+ abs(cur_inv_h_data - (cur_h + dy)) < 1 &&
326
+ abs(cur_inv_w_data - (cur_w + dx)) < 1)
327
+ {
328
+ int cur_bottom_grad_pos = ((b * channels + c) * height + cur_h + dy) * width + cur_w + dx;
329
+ scalar_t weight = get_gradient_weight(cur_inv_h_data, cur_inv_w_data, cur_h + dy, cur_w + dx, height, width);
330
+ atomicAdd(grad_im + cur_bottom_grad_pos, weight * cur_top_grad);
331
+ }
332
+ }
333
+ }
334
+ }
335
+ }
336
+
337
+ void deformable_col2im(
338
+ const at::Tensor data_col, const at::Tensor data_offset, const int channels,
339
+ const int height, const int width, const int ksize_h,
340
+ const int ksize_w, const int pad_h, const int pad_w,
341
+ const int stride_h, const int stride_w,
342
+ const int dilation_h, const int dilation_w,
343
+ const int parallel_imgs, const int deformable_group,
344
+ at::Tensor grad_im)
345
+ {
346
+
347
+ // todo: make sure parallel_imgs is passed in correctly
348
+ int height_col = (height + 2 * pad_h - (dilation_h * (ksize_h - 1) + 1)) / stride_h + 1;
349
+ int width_col = (width + 2 * pad_w - (dilation_w * (ksize_w - 1) + 1)) / stride_w + 1;
350
+ int num_kernels = channels * ksize_h * ksize_w * height_col * width_col * parallel_imgs;
351
+ int channel_per_deformable_group = channels / deformable_group;
352
+
353
+ AT_DISPATCH_FLOATING_TYPES_AND_HALF(
354
+ data_col.scalar_type(), "deformable_col2im_gpu", ([&] {
355
+ const scalar_t *data_col_ = data_col.data_ptr<scalar_t>();
356
+ const scalar_t *data_offset_ = data_offset.data_ptr<scalar_t>();
357
+ scalar_t *grad_im_ = grad_im.data_ptr<scalar_t>();
358
+
359
+ deformable_col2im_gpu_kernel<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS, 0, at::cuda::getCurrentCUDAStream()>>>(
360
+ num_kernels, data_col_, data_offset_, channels, height, width, ksize_h,
361
+ ksize_w, pad_h, pad_w, stride_h, stride_w,
362
+ dilation_h, dilation_w, channel_per_deformable_group,
363
+ parallel_imgs, deformable_group, height_col, width_col, grad_im_);
364
+ }));
365
+
366
+ cudaError_t err = cudaGetLastError();
367
+ if (err != cudaSuccess)
368
+ {
369
+ printf("error in deformable_col2im: %s\n", cudaGetErrorString(err));
370
+ }
371
+ }
372
+
373
+ template <typename scalar_t>
374
+ __global__ void deformable_col2im_coord_gpu_kernel(const int n, const scalar_t *data_col,
375
+ const scalar_t *data_im, const scalar_t *data_offset,
376
+ const int channels, const int height, const int width,
377
+ const int kernel_h, const int kernel_w,
378
+ const int pad_h, const int pad_w,
379
+ const int stride_h, const int stride_w,
380
+ const int dilation_h, const int dilation_w,
381
+ const int channel_per_deformable_group,
382
+ const int batch_size, const int offset_channels, const int deformable_group,
383
+ const int height_col, const int width_col, scalar_t *grad_offset)
384
+ {
385
+ CUDA_KERNEL_LOOP(index, n)
386
+ {
387
+ scalar_t val = 0;
388
+ int w = index % width_col;
389
+ int h = (index / width_col) % height_col;
390
+ int c = (index / width_col / height_col) % offset_channels;
391
+ int b = (index / width_col / height_col) / offset_channels;
392
+ // compute the start and end of the output
393
+
394
+ const int deformable_group_index = c / (2 * kernel_h * kernel_w);
395
+ const int col_step = kernel_h * kernel_w;
396
+ int cnt = 0;
397
+ const scalar_t *data_col_ptr = data_col + deformable_group_index * channel_per_deformable_group *
398
+ batch_size * width_col * height_col;
399
+ const scalar_t *data_im_ptr = data_im + (b * deformable_group + deformable_group_index) *
400
+ channel_per_deformable_group / kernel_h / kernel_w * height * width;
401
+ const scalar_t *data_offset_ptr = data_offset + (b * deformable_group + deformable_group_index) * 2 *
402
+ kernel_h * kernel_w * height_col * width_col;
403
+
404
+ const int offset_c = c - deformable_group_index * 2 * kernel_h * kernel_w;
405
+
406
+ for (int col_c = (offset_c / 2); col_c < channel_per_deformable_group; col_c += col_step)
407
+ {
408
+ const int col_pos = (((col_c * batch_size + b) * height_col) + h) * width_col + w;
409
+ const int bp_dir = offset_c % 2;
410
+
411
+ int j = (col_pos / width_col / height_col / batch_size) % kernel_w;
412
+ int i = (col_pos / width_col / height_col / batch_size / kernel_w) % kernel_h;
413
+ int w_out = col_pos % width_col;
414
+ int h_out = (col_pos / width_col) % height_col;
415
+ int w_in = w_out * stride_w - pad_w;
416
+ int h_in = h_out * stride_h - pad_h;
417
+ const int data_offset_h_ptr = (((2 * (i * kernel_w + j)) * height_col + h_out) * width_col + w_out);
418
+ const int data_offset_w_ptr = (((2 * (i * kernel_w + j) + 1) * height_col + h_out) * width_col + w_out);
419
+ const scalar_t offset_h = data_offset_ptr[data_offset_h_ptr];
420
+ const scalar_t offset_w = data_offset_ptr[data_offset_w_ptr];
421
+ scalar_t inv_h = h_in + i * dilation_h + offset_h;
422
+ scalar_t inv_w = w_in + j * dilation_w + offset_w;
423
+ if (inv_h <= -1 || inv_w <= -1 || inv_h >= height || inv_w >= width)
424
+ {
425
+ inv_h = inv_w = -2;
426
+ }
427
+ const scalar_t weight = get_coordinate_weight(
428
+ inv_h, inv_w,
429
+ height, width, data_im_ptr + cnt * height * width, width, bp_dir);
430
+ val += weight * data_col_ptr[col_pos];
431
+ cnt += 1;
432
+ }
433
+
434
+ grad_offset[index] = val;
435
+ }
436
+ }
437
+
438
+ void deformable_col2im_coord(
439
+ const at::Tensor data_col, const at::Tensor data_im, const at::Tensor data_offset,
440
+ const int channels, const int height, const int width, const int ksize_h,
441
+ const int ksize_w, const int pad_h, const int pad_w, const int stride_h,
442
+ const int stride_w, const int dilation_h, const int dilation_w,
443
+ const int parallel_imgs, const int deformable_group, at::Tensor grad_offset)
444
+ {
445
+
446
+ int height_col = (height + 2 * pad_h - (dilation_h * (ksize_h - 1) + 1)) / stride_h + 1;
447
+ int width_col = (width + 2 * pad_w - (dilation_w * (ksize_w - 1) + 1)) / stride_w + 1;
448
+ int num_kernels = height_col * width_col * 2 * ksize_h * ksize_w * deformable_group * parallel_imgs;
449
+ int channel_per_deformable_group = channels * ksize_h * ksize_w / deformable_group;
450
+
451
+ AT_DISPATCH_FLOATING_TYPES_AND_HALF(
452
+ data_col.scalar_type(), "deformable_col2im_coord_gpu", ([&] {
453
+ const scalar_t *data_col_ = data_col.data_ptr<scalar_t>();
454
+ const scalar_t *data_im_ = data_im.data_ptr<scalar_t>();
455
+ const scalar_t *data_offset_ = data_offset.data_ptr<scalar_t>();
456
+ scalar_t *grad_offset_ = grad_offset.data_ptr<scalar_t>();
457
+
458
+ deformable_col2im_coord_gpu_kernel<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS, 0, at::cuda::getCurrentCUDAStream()>>>(
459
+ num_kernels, data_col_, data_im_, data_offset_, channels, height, width,
460
+ ksize_h, ksize_w, pad_h, pad_w, stride_h, stride_w,
461
+ dilation_h, dilation_w, channel_per_deformable_group,
462
+ parallel_imgs, 2 * ksize_h * ksize_w * deformable_group, deformable_group,
463
+ height_col, width_col, grad_offset_);
464
+ }));
465
+ }
466
+
467
+ template <typename scalar_t>
468
+ __device__ scalar_t dmcn_im2col_bilinear(const scalar_t *bottom_data, const int data_width,
469
+ const int height, const int width, scalar_t h, scalar_t w)
470
+ {
471
+ int h_low = floor(h);
472
+ int w_low = floor(w);
473
+ int h_high = h_low + 1;
474
+ int w_high = w_low + 1;
475
+
476
+ scalar_t lh = h - h_low;
477
+ scalar_t lw = w - w_low;
478
+ scalar_t hh = 1 - lh, hw = 1 - lw;
479
+
480
+ scalar_t v1 = 0;
481
+ if (h_low >= 0 && w_low >= 0)
482
+ v1 = bottom_data[h_low * data_width + w_low];
483
+ scalar_t v2 = 0;
484
+ if (h_low >= 0 && w_high <= width - 1)
485
+ v2 = bottom_data[h_low * data_width + w_high];
486
+ scalar_t v3 = 0;
487
+ if (h_high <= height - 1 && w_low >= 0)
488
+ v3 = bottom_data[h_high * data_width + w_low];
489
+ scalar_t v4 = 0;
490
+ if (h_high <= height - 1 && w_high <= width - 1)
491
+ v4 = bottom_data[h_high * data_width + w_high];
492
+
493
+ scalar_t w1 = hh * hw, w2 = hh * lw, w3 = lh * hw, w4 = lh * lw;
494
+
495
+ scalar_t val = (w1 * v1 + w2 * v2 + w3 * v3 + w4 * v4);
496
+ return val;
497
+ }
498
+
499
+ template <typename scalar_t>
500
+ __device__ scalar_t dmcn_get_gradient_weight(scalar_t argmax_h, scalar_t argmax_w,
501
+ const int h, const int w, const int height, const int width)
502
+ {
503
+ if (argmax_h <= -1 || argmax_h >= height || argmax_w <= -1 || argmax_w >= width)
504
+ {
505
+ //empty
506
+ return 0;
507
+ }
508
+
509
+ int argmax_h_low = floor(argmax_h);
510
+ int argmax_w_low = floor(argmax_w);
511
+ int argmax_h_high = argmax_h_low + 1;
512
+ int argmax_w_high = argmax_w_low + 1;
513
+
514
+ scalar_t weight = 0;
515
+ if (h == argmax_h_low && w == argmax_w_low)
516
+ weight = (h + 1 - argmax_h) * (w + 1 - argmax_w);
517
+ if (h == argmax_h_low && w == argmax_w_high)
518
+ weight = (h + 1 - argmax_h) * (argmax_w + 1 - w);
519
+ if (h == argmax_h_high && w == argmax_w_low)
520
+ weight = (argmax_h + 1 - h) * (w + 1 - argmax_w);
521
+ if (h == argmax_h_high && w == argmax_w_high)
522
+ weight = (argmax_h + 1 - h) * (argmax_w + 1 - w);
523
+ return weight;
524
+ }
525
+
526
+ template <typename scalar_t>
527
+ __device__ scalar_t dmcn_get_coordinate_weight(scalar_t argmax_h, scalar_t argmax_w,
528
+ const int height, const int width, const scalar_t *im_data,
529
+ const int data_width, const int bp_dir)
530
+ {
531
+ if (argmax_h <= -1 || argmax_h >= height || argmax_w <= -1 || argmax_w >= width)
532
+ {
533
+ //empty
534
+ return 0;
535
+ }
536
+
537
+ int argmax_h_low = floor(argmax_h);
538
+ int argmax_w_low = floor(argmax_w);
539
+ int argmax_h_high = argmax_h_low + 1;
540
+ int argmax_w_high = argmax_w_low + 1;
541
+
542
+ scalar_t weight = 0;
543
+
544
+ if (bp_dir == 0)
545
+ {
546
+ if (argmax_h_low >= 0 && argmax_w_low >= 0)
547
+ weight += -1 * (argmax_w_low + 1 - argmax_w) * im_data[argmax_h_low * data_width + argmax_w_low];
548
+ if (argmax_h_low >= 0 && argmax_w_high <= width - 1)
549
+ weight += -1 * (argmax_w - argmax_w_low) * im_data[argmax_h_low * data_width + argmax_w_high];
550
+ if (argmax_h_high <= height - 1 && argmax_w_low >= 0)
551
+ weight += (argmax_w_low + 1 - argmax_w) * im_data[argmax_h_high * data_width + argmax_w_low];
552
+ if (argmax_h_high <= height - 1 && argmax_w_high <= width - 1)
553
+ weight += (argmax_w - argmax_w_low) * im_data[argmax_h_high * data_width + argmax_w_high];
554
+ }
555
+ else if (bp_dir == 1)
556
+ {
557
+ if (argmax_h_low >= 0 && argmax_w_low >= 0)
558
+ weight += -1 * (argmax_h_low + 1 - argmax_h) * im_data[argmax_h_low * data_width + argmax_w_low];
559
+ if (argmax_h_low >= 0 && argmax_w_high <= width - 1)
560
+ weight += (argmax_h_low + 1 - argmax_h) * im_data[argmax_h_low * data_width + argmax_w_high];
561
+ if (argmax_h_high <= height - 1 && argmax_w_low >= 0)
562
+ weight += -1 * (argmax_h - argmax_h_low) * im_data[argmax_h_high * data_width + argmax_w_low];
563
+ if (argmax_h_high <= height - 1 && argmax_w_high <= width - 1)
564
+ weight += (argmax_h - argmax_h_low) * im_data[argmax_h_high * data_width + argmax_w_high];
565
+ }
566
+
567
+ return weight;
568
+ }
569
+
570
+ template <typename scalar_t>
571
+ __global__ void modulated_deformable_im2col_gpu_kernel(const int n,
572
+ const scalar_t *data_im, const scalar_t *data_offset, const scalar_t *data_mask,
573
+ const int height, const int width, const int kernel_h, const int kernel_w,
574
+ const int pad_h, const int pad_w,
575
+ const int stride_h, const int stride_w,
576
+ const int dilation_h, const int dilation_w,
577
+ const int channel_per_deformable_group,
578
+ const int batch_size, const int num_channels, const int deformable_group,
579
+ const int height_col, const int width_col,
580
+ scalar_t *data_col)
581
+ {
582
+ CUDA_KERNEL_LOOP(index, n)
583
+ {
584
+ // index index of output matrix
585
+ const int w_col = index % width_col;
586
+ const int h_col = (index / width_col) % height_col;
587
+ const int b_col = (index / width_col / height_col) % batch_size;
588
+ const int c_im = (index / width_col / height_col) / batch_size;
589
+ const int c_col = c_im * kernel_h * kernel_w;
590
+
591
+ // compute deformable group index
592
+ const int deformable_group_index = c_im / channel_per_deformable_group;
593
+
594
+ const int h_in = h_col * stride_h - pad_h;
595
+ const int w_in = w_col * stride_w - pad_w;
596
+
597
+ scalar_t *data_col_ptr = data_col + ((c_col * batch_size + b_col) * height_col + h_col) * width_col + w_col;
598
+ //const float* data_im_ptr = data_im + ((b_col * num_channels + c_im) * height + h_in) * width + w_in;
599
+ const scalar_t *data_im_ptr = data_im + (b_col * num_channels + c_im) * height * width;
600
+ const scalar_t *data_offset_ptr = data_offset + (b_col * deformable_group + deformable_group_index) * 2 * kernel_h * kernel_w * height_col * width_col;
601
+
602
+ const scalar_t *data_mask_ptr = data_mask + (b_col * deformable_group + deformable_group_index) * kernel_h * kernel_w * height_col * width_col;
603
+
604
+ for (int i = 0; i < kernel_h; ++i)
605
+ {
606
+ for (int j = 0; j < kernel_w; ++j)
607
+ {
608
+ const int data_offset_h_ptr = ((2 * (i * kernel_w + j)) * height_col + h_col) * width_col + w_col;
609
+ const int data_offset_w_ptr = ((2 * (i * kernel_w + j) + 1) * height_col + h_col) * width_col + w_col;
610
+ const int data_mask_hw_ptr = ((i * kernel_w + j) * height_col + h_col) * width_col + w_col;
611
+ const scalar_t offset_h = data_offset_ptr[data_offset_h_ptr];
612
+ const scalar_t offset_w = data_offset_ptr[data_offset_w_ptr];
613
+ const scalar_t mask = data_mask_ptr[data_mask_hw_ptr];
614
+ scalar_t val = static_cast<scalar_t>(0);
615
+ const scalar_t h_im = h_in + i * dilation_h + offset_h;
616
+ const scalar_t w_im = w_in + j * dilation_w + offset_w;
617
+ //if (h_im >= 0 && w_im >= 0 && h_im < height && w_im < width) {
618
+ if (h_im > -1 && w_im > -1 && h_im < height && w_im < width)
619
+ {
620
+ //const float map_h = i * dilation_h + offset_h;
621
+ //const float map_w = j * dilation_w + offset_w;
622
+ //const int cur_height = height - h_in;
623
+ //const int cur_width = width - w_in;
624
+ //val = dmcn_im2col_bilinear(data_im_ptr, width, cur_height, cur_width, map_h, map_w);
625
+ val = dmcn_im2col_bilinear(data_im_ptr, width, height, width, h_im, w_im);
626
+ }
627
+ *data_col_ptr = val * mask;
628
+ data_col_ptr += batch_size * height_col * width_col;
629
+ //data_col_ptr += height_col * width_col;
630
+ }
631
+ }
632
+ }
633
+ }
634
+
635
+ template <typename scalar_t>
636
+ __global__ void modulated_deformable_col2im_gpu_kernel(const int n,
637
+ const scalar_t *data_col, const scalar_t *data_offset, const scalar_t *data_mask,
638
+ const int channels, const int height, const int width,
639
+ const int kernel_h, const int kernel_w,
640
+ const int pad_h, const int pad_w,
641
+ const int stride_h, const int stride_w,
642
+ const int dilation_h, const int dilation_w,
643
+ const int channel_per_deformable_group,
644
+ const int batch_size, const int deformable_group,
645
+ const int height_col, const int width_col,
646
+ scalar_t *grad_im)
647
+ {
648
+ CUDA_KERNEL_LOOP(index, n)
649
+ {
650
+ const int j = (index / width_col / height_col / batch_size) % kernel_w;
651
+ const int i = (index / width_col / height_col / batch_size / kernel_w) % kernel_h;
652
+ const int c = index / width_col / height_col / batch_size / kernel_w / kernel_h;
653
+ // compute the start and end of the output
654
+
655
+ const int deformable_group_index = c / channel_per_deformable_group;
656
+
657
+ int w_out = index % width_col;
658
+ int h_out = (index / width_col) % height_col;
659
+ int b = (index / width_col / height_col) % batch_size;
660
+ int w_in = w_out * stride_w - pad_w;
661
+ int h_in = h_out * stride_h - pad_h;
662
+
663
+ const scalar_t *data_offset_ptr = data_offset + (b * deformable_group + deformable_group_index) * 2 * kernel_h * kernel_w * height_col * width_col;
664
+ const scalar_t *data_mask_ptr = data_mask + (b * deformable_group + deformable_group_index) * kernel_h * kernel_w * height_col * width_col;
665
+ const int data_offset_h_ptr = ((2 * (i * kernel_w + j)) * height_col + h_out) * width_col + w_out;
666
+ const int data_offset_w_ptr = ((2 * (i * kernel_w + j) + 1) * height_col + h_out) * width_col + w_out;
667
+ const int data_mask_hw_ptr = ((i * kernel_w + j) * height_col + h_out) * width_col + w_out;
668
+ const scalar_t offset_h = data_offset_ptr[data_offset_h_ptr];
669
+ const scalar_t offset_w = data_offset_ptr[data_offset_w_ptr];
670
+ const scalar_t mask = data_mask_ptr[data_mask_hw_ptr];
671
+ const scalar_t cur_inv_h_data = h_in + i * dilation_h + offset_h;
672
+ const scalar_t cur_inv_w_data = w_in + j * dilation_w + offset_w;
673
+
674
+ const scalar_t cur_top_grad = data_col[index] * mask;
675
+ const int cur_h = (int)cur_inv_h_data;
676
+ const int cur_w = (int)cur_inv_w_data;
677
+ for (int dy = -2; dy <= 2; dy++)
678
+ {
679
+ for (int dx = -2; dx <= 2; dx++)
680
+ {
681
+ if (cur_h + dy >= 0 && cur_h + dy < height &&
682
+ cur_w + dx >= 0 && cur_w + dx < width &&
683
+ abs(cur_inv_h_data - (cur_h + dy)) < 1 &&
684
+ abs(cur_inv_w_data - (cur_w + dx)) < 1)
685
+ {
686
+ int cur_bottom_grad_pos = ((b * channels + c) * height + cur_h + dy) * width + cur_w + dx;
687
+ scalar_t weight = dmcn_get_gradient_weight(cur_inv_h_data, cur_inv_w_data, cur_h + dy, cur_w + dx, height, width);
688
+ atomicAdd(grad_im + cur_bottom_grad_pos, weight * cur_top_grad);
689
+ }
690
+ }
691
+ }
692
+ }
693
+ }
694
+
695
+ template <typename scalar_t>
696
+ __global__ void modulated_deformable_col2im_coord_gpu_kernel(const int n,
697
+ const scalar_t *data_col, const scalar_t *data_im,
698
+ const scalar_t *data_offset, const scalar_t *data_mask,
699
+ const int channels, const int height, const int width,
700
+ const int kernel_h, const int kernel_w,
701
+ const int pad_h, const int pad_w,
702
+ const int stride_h, const int stride_w,
703
+ const int dilation_h, const int dilation_w,
704
+ const int channel_per_deformable_group,
705
+ const int batch_size, const int offset_channels, const int deformable_group,
706
+ const int height_col, const int width_col,
707
+ scalar_t *grad_offset, scalar_t *grad_mask)
708
+ {
709
+ CUDA_KERNEL_LOOP(index, n)
710
+ {
711
+ scalar_t val = 0, mval = 0;
712
+ int w = index % width_col;
713
+ int h = (index / width_col) % height_col;
714
+ int c = (index / width_col / height_col) % offset_channels;
715
+ int b = (index / width_col / height_col) / offset_channels;
716
+ // compute the start and end of the output
717
+
718
+ const int deformable_group_index = c / (2 * kernel_h * kernel_w);
719
+ const int col_step = kernel_h * kernel_w;
720
+ int cnt = 0;
721
+ const scalar_t *data_col_ptr = data_col + deformable_group_index * channel_per_deformable_group * batch_size * width_col * height_col;
722
+ const scalar_t *data_im_ptr = data_im + (b * deformable_group + deformable_group_index) * channel_per_deformable_group / kernel_h / kernel_w * height * width;
723
+ const scalar_t *data_offset_ptr = data_offset + (b * deformable_group + deformable_group_index) * 2 * kernel_h * kernel_w * height_col * width_col;
724
+ const scalar_t *data_mask_ptr = data_mask + (b * deformable_group + deformable_group_index) * kernel_h * kernel_w * height_col * width_col;
725
+
726
+ const int offset_c = c - deformable_group_index * 2 * kernel_h * kernel_w;
727
+
728
+ for (int col_c = (offset_c / 2); col_c < channel_per_deformable_group; col_c += col_step)
729
+ {
730
+ const int col_pos = (((col_c * batch_size + b) * height_col) + h) * width_col + w;
731
+ const int bp_dir = offset_c % 2;
732
+
733
+ int j = (col_pos / width_col / height_col / batch_size) % kernel_w;
734
+ int i = (col_pos / width_col / height_col / batch_size / kernel_w) % kernel_h;
735
+ int w_out = col_pos % width_col;
736
+ int h_out = (col_pos / width_col) % height_col;
737
+ int w_in = w_out * stride_w - pad_w;
738
+ int h_in = h_out * stride_h - pad_h;
739
+ const int data_offset_h_ptr = (((2 * (i * kernel_w + j)) * height_col + h_out) * width_col + w_out);
740
+ const int data_offset_w_ptr = (((2 * (i * kernel_w + j) + 1) * height_col + h_out) * width_col + w_out);
741
+ const int data_mask_hw_ptr = (((i * kernel_w + j) * height_col + h_out) * width_col + w_out);
742
+ const scalar_t offset_h = data_offset_ptr[data_offset_h_ptr];
743
+ const scalar_t offset_w = data_offset_ptr[data_offset_w_ptr];
744
+ const scalar_t mask = data_mask_ptr[data_mask_hw_ptr];
745
+ scalar_t inv_h = h_in + i * dilation_h + offset_h;
746
+ scalar_t inv_w = w_in + j * dilation_w + offset_w;
747
+ if (inv_h <= -1 || inv_w <= -1 || inv_h >= height || inv_w >= width)
748
+ {
749
+ inv_h = inv_w = -2;
750
+ }
751
+ else
752
+ {
753
+ mval += data_col_ptr[col_pos] * dmcn_im2col_bilinear(data_im_ptr + cnt * height * width, width, height, width, inv_h, inv_w);
754
+ }
755
+ const scalar_t weight = dmcn_get_coordinate_weight(
756
+ inv_h, inv_w,
757
+ height, width, data_im_ptr + cnt * height * width, width, bp_dir);
758
+ val += weight * data_col_ptr[col_pos] * mask;
759
+ cnt += 1;
760
+ }
761
+ // KERNEL_ASSIGN(grad_offset[index], offset_req, val);
762
+ grad_offset[index] = val;
763
+ if (offset_c % 2 == 0)
764
+ // KERNEL_ASSIGN(grad_mask[(((b * deformable_group + deformable_group_index) * kernel_h * kernel_w + offset_c / 2) * height_col + h) * width_col + w], mask_req, mval);
765
+ grad_mask[(((b * deformable_group + deformable_group_index) * kernel_h * kernel_w + offset_c / 2) * height_col + h) * width_col + w] = mval;
766
+ }
767
+ }
768
+
769
+ void modulated_deformable_im2col_cuda(
770
+ const at::Tensor data_im, const at::Tensor data_offset, const at::Tensor data_mask,
771
+ const int batch_size, const int channels, const int height_im, const int width_im,
772
+ const int height_col, const int width_col, const int kernel_h, const int kenerl_w,
773
+ const int pad_h, const int pad_w, const int stride_h, const int stride_w,
774
+ const int dilation_h, const int dilation_w,
775
+ const int deformable_group, at::Tensor data_col)
776
+ {
777
+ // num_axes should be smaller than block size
778
+ const int channel_per_deformable_group = channels / deformable_group;
779
+ const int num_kernels = channels * batch_size * height_col * width_col;
780
+
781
+ AT_DISPATCH_FLOATING_TYPES_AND_HALF(
782
+ data_im.scalar_type(), "modulated_deformable_im2col_gpu", ([&] {
783
+ const scalar_t *data_im_ = data_im.data_ptr<scalar_t>();
784
+ const scalar_t *data_offset_ = data_offset.data_ptr<scalar_t>();
785
+ const scalar_t *data_mask_ = data_mask.data_ptr<scalar_t>();
786
+ scalar_t *data_col_ = data_col.data_ptr<scalar_t>();
787
+
788
+ modulated_deformable_im2col_gpu_kernel<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS, 0, at::cuda::getCurrentCUDAStream()>>>(
789
+ num_kernels, data_im_, data_offset_, data_mask_, height_im, width_im, kernel_h, kenerl_w,
790
+ pad_h, pad_w, stride_h, stride_w, dilation_h, dilation_w, channel_per_deformable_group,
791
+ batch_size, channels, deformable_group, height_col, width_col, data_col_);
792
+ }));
793
+
794
+ cudaError_t err = cudaGetLastError();
795
+ if (err != cudaSuccess)
796
+ {
797
+ printf("error in modulated_deformable_im2col_cuda: %s\n", cudaGetErrorString(err));
798
+ }
799
+ }
800
+
801
+ void modulated_deformable_col2im_cuda(
802
+ const at::Tensor data_col, const at::Tensor data_offset, const at::Tensor data_mask,
803
+ const int batch_size, const int channels, const int height_im, const int width_im,
804
+ const int height_col, const int width_col, const int kernel_h, const int kernel_w,
805
+ const int pad_h, const int pad_w, const int stride_h, const int stride_w,
806
+ const int dilation_h, const int dilation_w,
807
+ const int deformable_group, at::Tensor grad_im)
808
+ {
809
+
810
+ const int channel_per_deformable_group = channels / deformable_group;
811
+ const int num_kernels = channels * kernel_h * kernel_w * batch_size * height_col * width_col;
812
+
813
+ AT_DISPATCH_FLOATING_TYPES_AND_HALF(
814
+ data_col.scalar_type(), "modulated_deformable_col2im_gpu", ([&] {
815
+ const scalar_t *data_col_ = data_col.data_ptr<scalar_t>();
816
+ const scalar_t *data_offset_ = data_offset.data_ptr<scalar_t>();
817
+ const scalar_t *data_mask_ = data_mask.data_ptr<scalar_t>();
818
+ scalar_t *grad_im_ = grad_im.data_ptr<scalar_t>();
819
+
820
+ modulated_deformable_col2im_gpu_kernel<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS, 0, at::cuda::getCurrentCUDAStream()>>>(
821
+ num_kernels, data_col_, data_offset_, data_mask_, channels, height_im, width_im,
822
+ kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
823
+ dilation_h, dilation_w, channel_per_deformable_group,
824
+ batch_size, deformable_group, height_col, width_col, grad_im_);
825
+ }));
826
+
827
+ cudaError_t err = cudaGetLastError();
828
+ if (err != cudaSuccess)
829
+ {
830
+ printf("error in modulated_deformable_col2im_cuda: %s\n", cudaGetErrorString(err));
831
+ }
832
+ }
833
+
834
+ void modulated_deformable_col2im_coord_cuda(
835
+ const at::Tensor data_col, const at::Tensor data_im, const at::Tensor data_offset, const at::Tensor data_mask,
836
+ const int batch_size, const int channels, const int height_im, const int width_im,
837
+ const int height_col, const int width_col, const int kernel_h, const int kernel_w,
838
+ const int pad_h, const int pad_w, const int stride_h, const int stride_w,
839
+ const int dilation_h, const int dilation_w,
840
+ const int deformable_group,
841
+ at::Tensor grad_offset, at::Tensor grad_mask)
842
+ {
843
+ const int num_kernels = batch_size * height_col * width_col * 2 * kernel_h * kernel_w * deformable_group;
844
+ const int channel_per_deformable_group = channels * kernel_h * kernel_w / deformable_group;
845
+
846
+ AT_DISPATCH_FLOATING_TYPES_AND_HALF(
847
+ data_col.scalar_type(), "modulated_deformable_col2im_coord_gpu", ([&] {
848
+ const scalar_t *data_col_ = data_col.data_ptr<scalar_t>();
849
+ const scalar_t *data_im_ = data_im.data_ptr<scalar_t>();
850
+ const scalar_t *data_offset_ = data_offset.data_ptr<scalar_t>();
851
+ const scalar_t *data_mask_ = data_mask.data_ptr<scalar_t>();
852
+ scalar_t *grad_offset_ = grad_offset.data_ptr<scalar_t>();
853
+ scalar_t *grad_mask_ = grad_mask.data_ptr<scalar_t>();
854
+
855
+ modulated_deformable_col2im_coord_gpu_kernel<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS, 0, at::cuda::getCurrentCUDAStream()>>>(
856
+ num_kernels, data_col_, data_im_, data_offset_, data_mask_, channels, height_im, width_im,
857
+ kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
858
+ dilation_h, dilation_w, channel_per_deformable_group,
859
+ batch_size, 2 * kernel_h * kernel_w * deformable_group, deformable_group, height_col, width_col,
860
+ grad_offset_, grad_mask_);
861
+ }));
862
+ cudaError_t err = cudaGetLastError();
863
+ if (err != cudaSuccess)
864
+ {
865
+ printf("error in modulated_deformable_col2im_coord_cuda: %s\n", cudaGetErrorString(err));
866
+ }
867
+ }
basicsr/ops/dcn/src/deform_conv_ext.cpp ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // modify from
2
+ // https://github.com/chengdazhi/Deformable-Convolution-V2-PyTorch/blob/mmdetection/mmdet/ops/dcn/src/deform_conv_cuda.c
3
+
4
+ #include <torch/extension.h>
5
+ #include <ATen/DeviceGuard.h>
6
+
7
+ #include <cmath>
8
+ #include <vector>
9
+
10
+ #define WITH_CUDA // always use cuda
11
+ #ifdef WITH_CUDA
12
+ int deform_conv_forward_cuda(at::Tensor input, at::Tensor weight,
13
+ at::Tensor offset, at::Tensor output,
14
+ at::Tensor columns, at::Tensor ones, int kW,
15
+ int kH, int dW, int dH, int padW, int padH,
16
+ int dilationW, int dilationH, int group,
17
+ int deformable_group, int im2col_step);
18
+
19
+ int deform_conv_backward_input_cuda(at::Tensor input, at::Tensor offset,
20
+ at::Tensor gradOutput, at::Tensor gradInput,
21
+ at::Tensor gradOffset, at::Tensor weight,
22
+ at::Tensor columns, int kW, int kH, int dW,
23
+ int dH, int padW, int padH, int dilationW,
24
+ int dilationH, int group,
25
+ int deformable_group, int im2col_step);
26
+
27
+ int deform_conv_backward_parameters_cuda(
28
+ at::Tensor input, at::Tensor offset, at::Tensor gradOutput,
29
+ at::Tensor gradWeight, // at::Tensor gradBias,
30
+ at::Tensor columns, at::Tensor ones, int kW, int kH, int dW, int dH,
31
+ int padW, int padH, int dilationW, int dilationH, int group,
32
+ int deformable_group, float scale, int im2col_step);
33
+
34
+ void modulated_deform_conv_cuda_forward(
35
+ at::Tensor input, at::Tensor weight, at::Tensor bias, at::Tensor ones,
36
+ at::Tensor offset, at::Tensor mask, at::Tensor output, at::Tensor columns,
37
+ int kernel_h, int kernel_w, const int stride_h, const int stride_w,
38
+ const int pad_h, const int pad_w, const int dilation_h,
39
+ const int dilation_w, const int group, const int deformable_group,
40
+ const bool with_bias);
41
+
42
+ void modulated_deform_conv_cuda_backward(
43
+ at::Tensor input, at::Tensor weight, at::Tensor bias, at::Tensor ones,
44
+ at::Tensor offset, at::Tensor mask, at::Tensor columns,
45
+ at::Tensor grad_input, at::Tensor grad_weight, at::Tensor grad_bias,
46
+ at::Tensor grad_offset, at::Tensor grad_mask, at::Tensor grad_output,
47
+ int kernel_h, int kernel_w, int stride_h, int stride_w, int pad_h,
48
+ int pad_w, int dilation_h, int dilation_w, int group, int deformable_group,
49
+ const bool with_bias);
50
+ #endif
51
+
52
+ int deform_conv_forward(at::Tensor input, at::Tensor weight,
53
+ at::Tensor offset, at::Tensor output,
54
+ at::Tensor columns, at::Tensor ones, int kW,
55
+ int kH, int dW, int dH, int padW, int padH,
56
+ int dilationW, int dilationH, int group,
57
+ int deformable_group, int im2col_step) {
58
+ if (input.device().is_cuda()) {
59
+ #ifdef WITH_CUDA
60
+ return deform_conv_forward_cuda(input, weight, offset, output, columns,
61
+ ones, kW, kH, dW, dH, padW, padH, dilationW, dilationH, group,
62
+ deformable_group, im2col_step);
63
+ #else
64
+ AT_ERROR("deform conv is not compiled with GPU support");
65
+ #endif
66
+ }
67
+ AT_ERROR("deform conv is not implemented on CPU");
68
+ }
69
+
70
+ int deform_conv_backward_input(at::Tensor input, at::Tensor offset,
71
+ at::Tensor gradOutput, at::Tensor gradInput,
72
+ at::Tensor gradOffset, at::Tensor weight,
73
+ at::Tensor columns, int kW, int kH, int dW,
74
+ int dH, int padW, int padH, int dilationW,
75
+ int dilationH, int group,
76
+ int deformable_group, int im2col_step) {
77
+ if (input.device().is_cuda()) {
78
+ #ifdef WITH_CUDA
79
+ return deform_conv_backward_input_cuda(input, offset, gradOutput,
80
+ gradInput, gradOffset, weight, columns, kW, kH, dW, dH, padW, padH,
81
+ dilationW, dilationH, group, deformable_group, im2col_step);
82
+ #else
83
+ AT_ERROR("deform conv is not compiled with GPU support");
84
+ #endif
85
+ }
86
+ AT_ERROR("deform conv is not implemented on CPU");
87
+ }
88
+
89
+ int deform_conv_backward_parameters(
90
+ at::Tensor input, at::Tensor offset, at::Tensor gradOutput,
91
+ at::Tensor gradWeight, // at::Tensor gradBias,
92
+ at::Tensor columns, at::Tensor ones, int kW, int kH, int dW, int dH,
93
+ int padW, int padH, int dilationW, int dilationH, int group,
94
+ int deformable_group, float scale, int im2col_step) {
95
+ if (input.device().is_cuda()) {
96
+ #ifdef WITH_CUDA
97
+ return deform_conv_backward_parameters_cuda(input, offset, gradOutput,
98
+ gradWeight, columns, ones, kW, kH, dW, dH, padW, padH, dilationW,
99
+ dilationH, group, deformable_group, scale, im2col_step);
100
+ #else
101
+ AT_ERROR("deform conv is not compiled with GPU support");
102
+ #endif
103
+ }
104
+ AT_ERROR("deform conv is not implemented on CPU");
105
+ }
106
+
107
+ void modulated_deform_conv_forward(
108
+ at::Tensor input, at::Tensor weight, at::Tensor bias, at::Tensor ones,
109
+ at::Tensor offset, at::Tensor mask, at::Tensor output, at::Tensor columns,
110
+ int kernel_h, int kernel_w, const int stride_h, const int stride_w,
111
+ const int pad_h, const int pad_w, const int dilation_h,
112
+ const int dilation_w, const int group, const int deformable_group,
113
+ const bool with_bias) {
114
+ if (input.device().is_cuda()) {
115
+ #ifdef WITH_CUDA
116
+ return modulated_deform_conv_cuda_forward(input, weight, bias, ones,
117
+ offset, mask, output, columns, kernel_h, kernel_w, stride_h,
118
+ stride_w, pad_h, pad_w, dilation_h, dilation_w, group,
119
+ deformable_group, with_bias);
120
+ #else
121
+ AT_ERROR("modulated deform conv is not compiled with GPU support");
122
+ #endif
123
+ }
124
+ AT_ERROR("modulated deform conv is not implemented on CPU");
125
+ }
126
+
127
+ void modulated_deform_conv_backward(
128
+ at::Tensor input, at::Tensor weight, at::Tensor bias, at::Tensor ones,
129
+ at::Tensor offset, at::Tensor mask, at::Tensor columns,
130
+ at::Tensor grad_input, at::Tensor grad_weight, at::Tensor grad_bias,
131
+ at::Tensor grad_offset, at::Tensor grad_mask, at::Tensor grad_output,
132
+ int kernel_h, int kernel_w, int stride_h, int stride_w, int pad_h,
133
+ int pad_w, int dilation_h, int dilation_w, int group, int deformable_group,
134
+ const bool with_bias) {
135
+ if (input.device().is_cuda()) {
136
+ #ifdef WITH_CUDA
137
+ return modulated_deform_conv_cuda_backward(input, weight, bias, ones,
138
+ offset, mask, columns, grad_input, grad_weight, grad_bias, grad_offset,
139
+ grad_mask, grad_output, kernel_h, kernel_w, stride_h, stride_w,
140
+ pad_h, pad_w, dilation_h, dilation_w, group, deformable_group,
141
+ with_bias);
142
+ #else
143
+ AT_ERROR("modulated deform conv is not compiled with GPU support");
144
+ #endif
145
+ }
146
+ AT_ERROR("modulated deform conv is not implemented on CPU");
147
+ }
148
+
149
+
150
+ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
151
+ m.def("deform_conv_forward", &deform_conv_forward,
152
+ "deform forward");
153
+ m.def("deform_conv_backward_input", &deform_conv_backward_input,
154
+ "deform_conv_backward_input");
155
+ m.def("deform_conv_backward_parameters",
156
+ &deform_conv_backward_parameters,
157
+ "deform_conv_backward_parameters");
158
+ m.def("modulated_deform_conv_forward",
159
+ &modulated_deform_conv_forward,
160
+ "modulated deform conv forward");
161
+ m.def("modulated_deform_conv_backward",
162
+ &modulated_deform_conv_backward,
163
+ "modulated deform conv backward");
164
+ }