Skip to content

Commit 1433bf1

Browse files
Allow transposed convolution weights with a non-default dim order
1 parent 55a71e6 commit 1433bf1

2 files changed

Lines changed: 47 additions & 2 deletions

File tree

kernels/portable/cpu/util/kernel_ops_util.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,13 @@ bool check_convolution_args(
382382
ET_LOG_AND_RETURN_IF_FALSE(tensors_have_same_dtype(in, weight, out));
383383

384384
ET_LOG_AND_RETURN_IF_FALSE(tensor_is_default_or_channels_last_dim_order(in));
385-
ET_LOG_AND_RETURN_IF_FALSE(
386-
tensor_is_default_or_channels_last_dim_order(weight));
385+
// Transposed weights can have a non-default dim order (e.g. out_channels == 1
386+
// gives [1, 0, 2, 3]); the kernel indexes them by their strides, so any order
387+
// is valid here.
388+
if (!transposed) {
389+
ET_LOG_AND_RETURN_IF_FALSE(
390+
tensor_is_default_or_channels_last_dim_order(weight));
391+
}
387392
ET_LOG_AND_RETURN_IF_FALSE(tensor_is_default_or_channels_last_dim_order(out));
388393

389394
ET_CHECK_OR_RETURN_FALSE(

kernels/test/op_convolution_test.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -785,3 +785,43 @@ TEST_F(OpConvCorrectnessTest, BFloat16TypeSmokeTest) {
785785
out);
786786
EXPECT_TENSOR_CLOSE(out, expected);
787787
}
788+
789+
// Regression test for #20804: a transposed convolution weight with out_channels == 1
790+
// arrives with a non-default dim order (e.g. [1, 0, 2, 3], since the weight is laid out
791+
// as (in_channels, out_channels / groups, kH, kW)). The kernel indexes the weight through
792+
// its strides, so it must run and produce the same result as a default-order weight.
793+
TEST_F(OpConvCorrectnessTest, TransposedWeightNonDefaultDimOrder) {
794+
TensorFactory<ScalarType::Float> tf;
795+
796+
Tensor input = tf.make({1, 2, 2, 2}, {1, 2, 3, 4, 5, 6, 7, 8});
797+
798+
// Weight (in_channels=2, out_channels=1, kH=2, kW=2) in dim order [1, 0, 2, 3].
799+
Tensor weight = tf.make_with_dimorder(
800+
{2, 1, 2, 2}, {1, 2, 3, 4, 5, 6, 7, 8}, /*dim_order=*/{1, 0, 2, 3});
801+
802+
optional<Tensor> bias;
803+
Tensor out = tf.zeros({1, 1, 3, 3});
804+
Tensor expected =
805+
tf.make({1, 1, 3, 3}, {26, 64, 40, 76, 184, 112, 58, 136, 80});
806+
807+
int64_t stride[2] = {1, 1};
808+
int64_t padding[2] = {0, 0};
809+
int64_t dilation[2] = {1, 1};
810+
bool transposed = true;
811+
int64_t output_padding[2] = {0, 0};
812+
int64_t groups = 1;
813+
814+
op_convolution_out(
815+
input,
816+
weight,
817+
std::optional<Tensor>(bias),
818+
executorch::aten::ArrayRef<int64_t>{stride, 2},
819+
executorch::aten::ArrayRef<int64_t>{padding, 2},
820+
executorch::aten::ArrayRef<int64_t>{dilation, 2},
821+
transposed,
822+
executorch::aten::ArrayRef<int64_t>{output_padding, 2},
823+
groups,
824+
out);
825+
826+
EXPECT_TENSOR_CLOSE(out, expected);
827+
}

0 commit comments

Comments
 (0)