From f96f2225262ed9aaa17604aeb3185b98c5dc71d2 Mon Sep 17 00:00:00 2001 From: Jake Mathern Date: Tue, 18 Oct 2022 12:57:47 -0700 Subject: [PATCH] Change CPU EP behavior with auto_pad when ConvTranspose output shape is specified. (#13311) ### Description Based on the ORT spec for ConvTranspose: ``` output_shape can also be explicitly specified in which case pads values are auto generated using these equations: total_padding[i] = stride[i] * (input_size[i] - 1) + output_padding[i] + ((kernel_shape[i] - 1) * dilations[i] + 1) - output_shape[i] If (auto_pads == SAME_UPPER): pads[start_i] = total_padding[i]/2; pads[end_i] = total_padding[i] - (total_padding[i]/2) Else: pads[start_i] = total_padding[i] - (total_padding[i]/2); pads[end_i] = (total_padding[i]/2). ``` However the CPU EP logic differs. Basically, unless SAME_UPPER is specified, the default behavior (for VALID,NOTSET,SAME_LOWER) should be SAME_LOWER. I think this is the pragmatic fix, however it's perhaps still not totally up to standard. In the case tested, the operator is actually only valid if padding is inserted. Perhaps it "should" throw some error then, if auto_pad is not SAME_UPPER or SAME_LOWER, as the spec also mentions: "VALID mean no padding." (For convtranspose-1 but this was removed in convtranspose-11, making it less clear.) "NOTSET, which means explicit padding is used" (should technically require explicit padding then, and not generate it) HOWEVER, changing it to throw errors could do more harm than good. For now, probably just best to make it consistent. ### Motivation and Context We noticed that there was a discrepancy in one of the DML tests between CPU and DML. auto_pad is not specified, and DML is doing SAME_LOWER behavior by default, where CPU EP is doing SAME_UPPER behavior. ```json { "graph_name": "ConvTranspose output_shape with even strides odd kernel autopad NOTSET", "op_type": "ConvTranspose", "dilations": [1,1], "group": 1, "strides": [2,2], "kernel_shape": [3,3], "output_shape": [1,1,4,4], "X": {"dims": [1,1,2,2], "function": "iota"}, "W": {"dims": [1,1,3,3], "value": [1,2,3,4,5,6,7,8,9]}, "B": [1], "Y": {"dims": [1,1,4,4], "value": [1,5,6,7,5,17,15,19,11,25,16,19,17,40,25,28]}, "T": "float32" } ``` --- .../providers/cpu/nn/conv_transpose_attributes.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/onnxruntime/core/providers/cpu/nn/conv_transpose_attributes.h b/onnxruntime/core/providers/cpu/nn/conv_transpose_attributes.h index 7d0bc28708..b0af505965 100644 --- a/onnxruntime/core/providers/cpu/nn/conv_transpose_attributes.h +++ b/onnxruntime/core/providers/cpu/nn/conv_transpose_attributes.h @@ -176,15 +176,15 @@ struct ConvTransposeAttributes : public ConvAttributes { void DistributePadding(AutoPadType pad_type, const int64_t& total_pad, int64_t& pad_head, int64_t& pad_tail) const { - if (pad_type == AutoPadType::SAME_LOWER) { // pad more on head when total_pad is odd. - pad_head = total_pad - total_pad / 2; - pad_tail = total_pad / 2; - } else { - // for pad_type is NOTSET, SAME_LOWER or VALID - // set pad_head as total_pad/2, pad_tail as total_pad-total_pad/2. - // That said, we pad more on tail when total_pad is odd. + if (pad_type == AutoPadType::SAME_UPPER) { + // pad more on tail when total_pad is odd. pad_head = total_pad / 2; pad_tail = total_pad - total_pad / 2; + } else { + // When pad_type is NOTSET, SAME_LOWER or VALID, + // pad more on head when total_pad is odd. + pad_head = total_pad - total_pad / 2; + pad_tail = total_pad / 2; } }