Skip to content

Commit de24652

Browse files
manuelcandalesfacebook-github-bot
authored andcommitted
transposed convolution: add channels last tests (#4208)
Summary: Pull Request resolved: #4208 Differential Revision: D59622072
1 parent 074a81e commit de24652

File tree

2 files changed

+128
-17
lines changed

2 files changed

+128
-17
lines changed

kernels/portable/cpu/op_convolution.cpp

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -136,17 +136,6 @@ void conv2d_impl(
136136
}
137137
}
138138
} else { // transposed convolution
139-
if (bias_ptr != nullptr) {
140-
out_coord[2] = 0;
141-
out_coord[3] = 0;
142-
size_t out_c_start_idx =
143-
calculate_linear_index(out_coord, out_strides.data(), 4);
144-
size_t out_c_end_idx = out_c_start_idx + out_H * out_W;
145-
for (size_t out_ix = out_c_start_idx; out_ix < out_c_end_idx; out_ix++) {
146-
out_ptr[out_ix] = convert<CTYPE, CTYPE_BIAS>(bias_ptr[out_c]);
147-
}
148-
}
149-
150139
w_coord[1] = out_c - out_c_start;
151140

152141
for (size_t in_y = 0; in_y < in_H; ++in_y) {
@@ -295,12 +284,22 @@ void convolution_wrapper(
295284
bias.has_value() ? bias.value().const_data_ptr<CTYPE_BIAS>() : nullptr;
296285

297286
size_t out_N = out.size(0);
298-
size_t out_C_per_group = out.size(1) / groups;
287+
size_t out_C = out.size(1);
288+
size_t out_C_per_group = out_C / groups;
299289

300-
if (transposed && bias_ptr == nullptr) {
301-
// If bias is not present, we need to initialize the output to 0
302-
// before we can accumulate into it.
303-
memset(out_ptr, 0, out.nbytes());
290+
if (transposed) {
291+
// For transposed convolution, we need to initialized the output before we
292+
// can accumulate into it.
293+
if (bias_ptr == nullptr) {
294+
// If bias is not present, we need to initialize the output to 0
295+
memset(out_ptr, 0, out.nbytes());
296+
} else {
297+
// If bias is present, we initialize the output to the bias value
298+
for (size_t out_ix = 0; out_ix < out.numel(); ++out_ix) {
299+
out_ptr[out_ix] = convert<CTYPE, CTYPE_BIAS>(
300+
bias_ptr[(out_ix / out_strides[1]) % out_C]);
301+
}
302+
}
304303
}
305304

306305
for (size_t batch = 0; batch < out_N; ++batch) {

kernels/test/op_convolution_test.cpp

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ TEST_F(OpConvCorrectnessTest, TransposedNonDefaultParams) {
556556
Tensor input = tf.full({2, 6, 4, 5}, 2.0);
557557
Tensor weight = tf.full({6, 1, 2, 2}, 0.5);
558558
Tensor bias = tf.make({3}, {1, 2, 3});
559-
Tensor out = tf.zeros({2, 3, 3, 6});
559+
Tensor out = tf.full({2, 3, 3, 6}, 0.7);
560560
Tensor expected = tf.make(
561561
{2, 3, 3, 6},
562562
{1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 3, 3, 2, 2, 2, 2,
@@ -587,6 +587,118 @@ TEST_F(OpConvCorrectnessTest, TransposedNonDefaultParams) {
587587
EXPECT_TENSOR_CLOSE(out, expected);
588588
}
589589

590+
template <typename T>
591+
std::vector<T> get_channels_last_data(const Tensor& t) {
592+
const std::vector<int32_t> sizes(t.sizes().begin(), t.sizes().end());
593+
std::vector<T> contiguous_data(
594+
t.const_data_ptr<T>(), t.const_data_ptr<T>() + t.numel());
595+
std::vector<T> channels_last_data(t.numel());
596+
int32_t N = sizes[0];
597+
int32_t C = sizes[1];
598+
int32_t H = sizes[2];
599+
int32_t W = sizes[3];
600+
for (int32_t n = 0; n < N; ++n) {
601+
for (int32_t c = 0; c < C; ++c) {
602+
for (int32_t h = 0; h < H; ++h) {
603+
for (int32_t w = 0; w < W; ++w) {
604+
// Calculate the index in the original blob
605+
int32_t old_index = ((n * C + c) * H + h) * W + w;
606+
// Calculate the index in the new blob
607+
int32_t new_index = ((n * H + h) * W + w) * C + c;
608+
// Copy the data
609+
channels_last_data[new_index] = contiguous_data[old_index];
610+
}
611+
}
612+
}
613+
}
614+
return channels_last_data;
615+
}
616+
617+
TEST_F(OpConvCorrectnessTest, TransposedDefaultParamsChannelsLast) {
618+
TensorFactory<ScalarType::Float> tf;
619+
620+
Tensor input = tf.full_channels_last({2, 4, 3, 2}, 2.0);
621+
Tensor weight = tf.full_channels_last({4, 1, 2, 2}, 0.5);
622+
optional<Tensor> bias;
623+
Tensor out = tf.full_channels_last({2, 2, 4, 3}, 0.7);
624+
Tensor expected =
625+
tf.make({2, 2, 4, 3}, {2, 4, 2, 4, 8, 4, 4, 8, 4, 2, 4, 2, 2, 4, 2, 4,
626+
8, 4, 4, 8, 4, 2, 4, 2, 2, 4, 2, 4, 8, 4, 4, 8,
627+
4, 2, 4, 2, 2, 4, 2, 4, 8, 4, 4, 8, 4, 2, 4, 2});
628+
629+
const std::vector<int32_t> sizes(
630+
expected.sizes().begin(), expected.sizes().end());
631+
std::vector<float> channels_last_data =
632+
get_channels_last_data<float>(expected);
633+
Tensor expected_channels_last =
634+
tf.make_channels_last(sizes, channels_last_data);
635+
636+
int64_t stride[1] = {1};
637+
int64_t padding[1] = {0};
638+
int64_t dilation[1] = {1};
639+
bool transposed = true;
640+
int64_t output_padding[1] = {0};
641+
int64_t groups = 2;
642+
643+
op_convolution_out(
644+
input,
645+
weight,
646+
exec_aten::optional<Tensor>(bias),
647+
exec_aten::ArrayRef<int64_t>{stride, 1},
648+
exec_aten::ArrayRef<int64_t>{padding, 1},
649+
exec_aten::ArrayRef<int64_t>{dilation, 1},
650+
transposed,
651+
exec_aten::ArrayRef<int64_t>{output_padding, 1},
652+
groups,
653+
out);
654+
655+
EXPECT_TENSOR_CLOSE(out, expected_channels_last);
656+
}
657+
658+
TEST_F(OpConvCorrectnessTest, TransposedNonDefaultParamsChannelsLast) {
659+
TensorFactory<ScalarType::Float> tf;
660+
661+
Tensor input = tf.full_channels_last({2, 6, 4, 5}, 2.0);
662+
Tensor weight = tf.full_channels_last({6, 1, 2, 2}, 0.5);
663+
Tensor bias = tf.make({3}, {1, 2, 3});
664+
Tensor out = tf.full_channels_last({2, 3, 3, 6}, 0.7);
665+
Tensor expected = tf.make(
666+
{2, 3, 3, 6},
667+
{1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 3, 3, 2, 2, 2, 2,
668+
2, 2, 2, 4, 4, 2, 4, 4, 2, 4, 4, 2, 4, 4, 3, 3, 3, 3, 3, 3, 3, 5,
669+
5, 3, 5, 5, 3, 5, 5, 3, 5, 5, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, 3,
670+
1, 3, 3, 1, 3, 3, 2, 2, 2, 2, 2, 2, 2, 4, 4, 2, 4, 4, 2, 4, 4, 2,
671+
4, 4, 3, 3, 3, 3, 3, 3, 3, 5, 5, 3, 5, 5, 3, 5, 5, 3, 5, 5});
672+
673+
const std::vector<int32_t> sizes(
674+
expected.sizes().begin(), expected.sizes().end());
675+
std::vector<float> channels_last_data =
676+
get_channels_last_data<float>(expected);
677+
Tensor expected_channels_last =
678+
tf.make_channels_last(sizes, channels_last_data);
679+
680+
int64_t stride[1] = {3};
681+
int64_t padding[1] = {7};
682+
int64_t dilation[1] = {5};
683+
bool transposed = true;
684+
int64_t output_padding[1] = {2};
685+
int64_t groups = 3;
686+
687+
op_convolution_out(
688+
input,
689+
weight,
690+
exec_aten::optional<Tensor>(bias),
691+
exec_aten::ArrayRef<int64_t>{stride, 1},
692+
exec_aten::ArrayRef<int64_t>{padding, 1},
693+
exec_aten::ArrayRef<int64_t>{dilation, 1},
694+
transposed,
695+
exec_aten::ArrayRef<int64_t>{output_padding, 1},
696+
groups,
697+
out);
698+
699+
EXPECT_TENSOR_CLOSE(out, expected_channels_last);
700+
}
701+
590702
TEST_F(OpConvCorrectnessTest, InvalidOutputPadding) {
591703
TensorFactory<ScalarType::Float> tf;
592704

0 commit comments

Comments
 (0)