Add dynamic shape support for ONNX Conv to Linalg lowering#3388
Add dynamic shape support for ONNX Conv to Linalg lowering#3388
Conversation
|
Can one of the admins verify this patch? |
|
In your example, could you include all the details, such as constant %c* and maps? If a dimension size is not a affine function (not in ConvOp case), what dialect can be used to express the expression? Or when the output tensor shape of an Op can not be expressed with affine, this Op can not be lowered to Linalg. Is it true? |
|
Hi, @chentong319 ! Thanks for your review. 1. Example with All Details (Constants %c* and Maps)Here is the complete example with all details from the actual generated code: #map = affine_map<(d0) -> (d0 - 2)>
#map1 = affine_map<(d0, d1) -> (d1 - 2)>
module {
func.func @conv_dynamic(%arg0: tensor<?x3x?x?xf32>, %arg1: tensor<2x3x3x3xf32>) -> tensor<?x2x?x?xf32> {
%cst = arith.constant 0.000000e+00 : f32
%c3 = arith.constant 3 : index
%c2 = arith.constant 2 : index
%c0 = arith.constant 0 : index
%dim = tensor.dim %arg0, %c0 : tensor<?x3x?x?xf32>
%dim_0 = tensor.dim %arg0, %c2 : tensor<?x3x?x?xf32>
%0 = affine.apply #map(%dim_0)
%dim_1 = tensor.dim %arg0, %c3 : tensor<?x3x?x?xf32>
%1 = affine.apply #map1(%dim_0, %dim_1)
%2 = tensor.empty(%dim, %0, %1) : tensor<?x2x?x?xf32>
%3 = linalg.fill ins(%cst : f32) outs(%2 : tensor<?x2x?x?xf32>) -> tensor<?x2x?x?xf32>
%4 = linalg.conv_2d_nchw_fchw {dilations = dense<1> : tensor<2xi64>, strides = dense<1> : tensor<2xi64>} ins(%arg0, %arg1 : tensor<?x3x?x?xf32>, tensor<2x3x3x3xf32>) outs(%3 : tensor<?x2x?x?xf32>) -> tensor<?x2x?x?xf32>
return %4 : tensor<?x2x?x?xf32>
}
}You can check it by running 2. Non-Affine Dimension Size ExpressionsWhen a dimension size is not an affine function (e.g., division by a variable, complex expressions), the How it works: The
3. Can Operations with Non-Affine Output Shapes be Lowered to Linalg?Answer: Yes, they can be lowered to Linalg. The key insight is that Linalg operations themselves use affine indexing maps, but the output tensor shape computation (which happens before creating the tensor) is separate and can use any dialect operations.
|
|
I like the idea of extension IndexExpr. Shall we discuss on adding the destination-passing interface on onnx ops in issue #3355? We can schedule a meeting to discuss how to add DestinationStyleOpInterface to onnx op. We can refactor the code that generate the output memref for ops in onnx-to-krnl conversion into reifyResultShapes of onnx ops. That code can be shared by multiple users. You do not need to deal it only for Linalg. |
|
That sounds like a great plan, @chentong319! |
|
I lost my slack account for onnx-mlir-discussion. Let's start discussion in issue 3355. |
Changes
IndexExprBuilderForLinalgtensor::EmptyOpcreationTesting
conv_dynamictest case intest/mlir/conversion/onnx_to_linalg/NN/Conv.mlirtensor<?x3x?x?xf32>tensor<?x2x?x?xf32>tensor.dim,affine.apply, andtensor.emptywith dynamic sizes are generated correctlyExample
Before (static only):
After (dynamic support):
Related