mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-26 19:52:38 +00:00
Add shape inference to ConvTransposeWithDynamicPads schema (#2632)
This commit is contained in:
parent
4dbf9442cc
commit
ac08b58867
1 changed files with 137 additions and 3 deletions
|
|
@ -27,6 +27,142 @@ void matmulShapeInference(
|
|||
ONNX_NAMESPACE::InferenceContext& ctx,
|
||||
int input1Idx,
|
||||
int input2Idx);
|
||||
|
||||
void convTransposeWithDynamicPadsShapeInference(InferenceContext& ctx) {
|
||||
propagateElemTypeFromInputToOutput(ctx, 0, 0);
|
||||
|
||||
// we need at least two inputs to have a shape for this inference.
|
||||
if (!hasNInputShapes(ctx, 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t group = getAttribute(ctx, "group", 1);
|
||||
|
||||
auto input_shape = ctx.getInputType(0)->tensor_type().shape();
|
||||
if (input_shape.dim_size() < 2) {
|
||||
return; // Input tensor should have at least two dimensions.
|
||||
}
|
||||
|
||||
// first dim is the batch axis and the next is the number of channels.
|
||||
size_t n_input_dims = static_cast<size_t>(input_shape.dim_size() - 2);
|
||||
|
||||
std::vector<int64_t> dilations;
|
||||
if (getRepeatedAttribute(ctx, "dilations", dilations)) {
|
||||
if (dilations.size() != n_input_dims) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
dilations.assign(n_input_dims, 1);
|
||||
}
|
||||
|
||||
std::vector<int64_t> strides;
|
||||
if (getRepeatedAttribute(ctx, "strides", strides)) {
|
||||
if (strides.size() != n_input_dims) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
strides.assign(n_input_dims, 1);
|
||||
}
|
||||
|
||||
std::vector<int64_t> kernel_shape;
|
||||
if (getRepeatedAttribute(ctx, "kernel_shape", kernel_shape)) {
|
||||
if (kernel_shape.size() != n_input_dims) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
auto second_input_shape = ctx.getInputType(1)->tensor_type().shape();
|
||||
for (int i = 2; i < second_input_shape.dim_size(); ++i) {
|
||||
if (!second_input_shape.dim(i).has_dim_value()) {
|
||||
return;
|
||||
}
|
||||
kernel_shape.push_back(second_input_shape.dim(i).dim_value());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int64_t> effective_kernel_shape = kernel_shape;
|
||||
for (int i = 0; i < static_cast<int>(kernel_shape.size()); i++) {
|
||||
// accounting for dilation, how big is the kernel in this dimension
|
||||
effective_kernel_shape[i] =
|
||||
(effective_kernel_shape[i] - 1) * dilations[i] + 1;
|
||||
}
|
||||
|
||||
std::vector<int64_t> pads;
|
||||
|
||||
// Infer output shape if 'pads' tensor is available
|
||||
const auto* pads_initializer = ctx.getInputData(2);
|
||||
if (nullptr == pads_initializer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pads_initializer->dims_size() != 1 ||
|
||||
pads_initializer->data_type() != TensorProto::INT64)
|
||||
fail_shape_inference(
|
||||
"'pads' input must be a 1D (shape: [2 * n_input_dims]) tensor of type int64");
|
||||
|
||||
pads = ParseData<int64_t>(pads_initializer);
|
||||
|
||||
if (pads.size() != static_cast<size_t>(2 * n_input_dims))
|
||||
fail_shape_inference("Pads has incorrect number of values");
|
||||
|
||||
std::vector<int64_t> output_shape;
|
||||
bool output_shape_presented = true;
|
||||
if (getRepeatedAttribute(ctx, "output_shape", output_shape)) {
|
||||
if (output_shape.size() != n_input_dims) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
output_shape_presented = false;
|
||||
}
|
||||
|
||||
std::vector<int64_t> output_padding;
|
||||
if (getRepeatedAttribute(ctx, "output_padding", output_padding)) {
|
||||
if (output_padding.size() != n_input_dims) { // Added only to one side.
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
output_padding.assign(n_input_dims, 0);
|
||||
}
|
||||
|
||||
auto final_output_shape =
|
||||
ctx.getOutputType(0)->mutable_tensor_type()->mutable_shape();
|
||||
|
||||
*final_output_shape->add_dim() = input_shape.dim(0);
|
||||
*final_output_shape->add_dim() =
|
||||
ctx.getInputType(1)->tensor_type().shape().dim(1) *
|
||||
group; // channels should be the second dim of second input multiply
|
||||
// group.
|
||||
|
||||
int size_of_output;
|
||||
if (output_shape_presented) {
|
||||
size_of_output = static_cast<int>(output_shape.size());
|
||||
for (int i = 0; i < size_of_output; ++i) {
|
||||
if (input_shape.dim(i + 2).has_dim_value()) {
|
||||
if (output_shape[i] < input_shape.dim(i + 2).dim_value()) {
|
||||
// TODO: throw exception?
|
||||
return; // output shape value cannot be smaller than the input shape
|
||||
// value
|
||||
}
|
||||
}
|
||||
final_output_shape->add_dim()->set_dim_value(output_shape[i]);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
size_of_output = input_shape.dim_size() - 2;
|
||||
for (int i = 0; i < size_of_output; ++i) {
|
||||
if (input_shape.dim(i + 2).has_dim_value()) {
|
||||
int64_t output_shape_dim =
|
||||
strides[i] * (input_shape.dim(i + 2).dim_value() - 1) +
|
||||
output_padding[i] + effective_kernel_shape[i] - pads[i] -
|
||||
pads[i + n_input_dims];
|
||||
final_output_shape->add_dim()->set_dim_value(output_shape_dim);
|
||||
} else {
|
||||
final_output_shape->add_dim();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ONNX_NAMESPACE
|
||||
|
||||
namespace onnxruntime {
|
||||
|
|
@ -914,9 +1050,7 @@ Sample echo operator.)DOC");
|
|||
"",
|
||||
"T")
|
||||
.TypeConstraint("T", {"tensor(float16)", "tensor(float)", "tensor(double)"}, "Constrain input and output types to float tensors")
|
||||
.TypeAndShapeInferenceFunction([](ONNX_NAMESPACE::InferenceContext& ctx) {
|
||||
propagateElemTypeFromInputToOutput(ctx, 0, 0);
|
||||
});
|
||||
.TypeAndShapeInferenceFunction(ONNX_NAMESPACE::convTransposeWithDynamicPadsShapeInference);
|
||||
|
||||
ONNX_CONTRIB_OPERATOR_SCHEMA(FusedConv)
|
||||
.SetDomain(kMSDomain)
|
||||
|
|
|
|||
Loading…
Reference in a new issue