This is an archive of the discontinued LLVM Phabricator instance.

[mlir][LinAlg][Transform] Add a transform op for conv2d to im2col
ClosedPublic

Authored by qcolombet on Feb 15 2023, 8:13 AM.

Details

Summary

This patch adds patterns to convert linalg.conv_2d_xxx operations
into linalg.generic (for img2col packing) and linalg.matmul.

The meat of the patch comes straight from IREE
(https://github.com/iree-org/iree).
(To the original authors are you okay with that?)

What this patch adds is proper plumbing of the im2col patterns into the
transform dialect.

PS: Feel free to add more reviewers. I wanted to cover the original contributors of im2col in IREE but I'm not sure I got all of them.

Diff Detail

Event Timeline

qcolombet created this revision.Feb 15 2023, 8:13 AM
qcolombet requested review of this revision.Feb 15 2023, 8:13 AM

I will let others review the transform dialect piece, but I see the movement of these patterns from IREE as a step in the right direction. Also, it would probably be good to pull the FileCheck tests from IREE as well, even if the intent is to later generalize the patterns as the transform won't change.

nicolasvasilache accepted this revision.Feb 15 2023, 8:52 AM

LGTM for the TD part.

As a followup, we should build a utility that is able to take 2 AffineDimExpr such that we have an indexing of the form:

LHS(..., a * d0 + b * d1, ...), RHS(..., d1, ...), RES(..., d0, ...)

and data-unroll/replicate the LHS along d1.

This should be a small 1-D utility based on a simple inference that resembles what has been introduced in https://reviews.llvm.org/D142661 https://reviews.llvm.org/D143584.
Then we can reuse the utility to work on any LinalgOp and avoid special casing 1-off C++ patterns.

This revision is now accepted and ready to land.Feb 15 2023, 8:52 AM
nicolasvasilache requested changes to this revision.EditedFeb 15 2023, 8:55 AM

Actually sorry, this needs a test.
We should also return multiple handles to capture the unrolling and the unrolled op (and test that 2 ssa values of the proper type are indeed returned).

This revision now requires changes to proceed.Feb 15 2023, 8:55 AM

I think it's good to see the im2col is being upstreamed.

mravishankar requested changes to this revision.Feb 15 2023, 10:55 AM

I know this pattern exists in IREE, but it is a bit of a hack. The representation of the im2col as a linalg.generic doesnt work as well. In reality it is similar to a gather. If this is upstreamed, it might be worth doing this right and not use an unnecessarily higher-dimensional operation for representing the im2col. Maybe we can chat offline?

My bad on the test, I forgot to do git add, fixing that now.

  • git add the test

@nicolasvasilache, @mravishankar, I think it makes sense to upstream the version we have from IREE as is and iterate to make it better.
If anything I believe it would make the review easier.

In other words, how do you feel about having followup patches for changing the results to have several handles and using a gather like op?

These patterns look very similar, any chance they can be generalized somehow?

mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
1721

It would be nice to give a more ample description. This is user-visible on the website...

1724

Please do not use === with is the h1 header. Use leading #### instead to get a h4 that this should be.

1729–1730

New operations must no longer hardcode PDL_Operation as a type. Use the type TransformHandleTypeInterfaceinstead and specify the type in the assembly format.

mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
3077–3080

Do we actually need the entire greedy rewriter for this, including all the pseudo-canonicalization and DCE stuff it carries? This is applying three patterns that seem mutually exclusive. Can't we just apply patterns one-by-one? With a tiny bit of effort, we can even be more informative as to what didn't match.

mlir/lib/Dialect/Linalg/Transforms/ConvertConv2DToImg2Col.cpp
32

Can't we query this from x.getType()?

91

Nit: return rewriter.notifyMatchFailure helps with debugging.

102

Nit: please expand auto.

105

We don't do const variables in MLIR.

115

Nit: drop the number of stack elements, here and below.

374

Nit: please expand auto when the type is reasonable to spell and not obvious from the context. I've got no idea what it should be here.

386

Same comments as above apply below.

These patterns look very similar, any chance they can be generalized somehow?

Maybe. I haven't really looked into them, the meat of the patch is literally a copy/paste of the IREE version (hence me asking the original authors whether or not they are okay with that.)

I know this pattern exists in IREE, but it is a bit of a hack. The representation of the im2col as a linalg.generic doesnt work as well. In reality it is similar to a gather. If this is upstreamed, it might be worth doing this right and not use an unnecessarily higher-dimensional operation for representing the im2col. Maybe we can chat offline?

These patterns look very similar, any chance they can be generalized somehow?

Please read my reply, this is why I wrote:

As a followup, we should build a utility that is able to take 2 AffineDimExpr such that we have an indexing of the form:

LHS(..., a * d0 + b * d1, ...), RHS(..., d1, ...), RES(..., d0, ...)
and data-unroll/replicate the LHS along d1.

This should be a small 1-D utility based on a simple inference that resembles what has been introduced in https://reviews.llvm.org/D142661 https://reviews.llvm.org/D143584.
Then we can reuse the utility to work on any LinalgOp and avoid special casing 1-off C++ patterns.

@nicolasvasilache, @mravishankar, I think it makes sense to upstream the version we have from IREE as is and iterate to make it better.
If anything I believe it would make the review easier.

In other words, how do you feel about having followup patches for changing the results to have several handles and using a gather like op?

It would make sense for me to start from an existing solution that we can then generalize.
If we want the generalization to exist first this would work too but I would then table this for a few days (maybe weeks) until we get it right.

mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
3077–3080

strong +1 to this.

Cutting a little deeper to drop the driver like I am doing here https://reviews.llvm.org/D143943 would be very welcome.

mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
3077–3080

IOW this is a simple additional refactoring:

  1. extract the functional-style transformation into its own well-defined API,
  2. have the pattern merely wrap calls to that API + populate method,
  3. transform dialect op calls the API directly.
qcolombet updated this revision to Diff 498280.Feb 17 2023, 1:14 AM
  • Have the transform apply to the conv operation directly (as opposed to the whole function)
  • Ditch the call to the greedy rewriter
mlir/lib/Dialect/Linalg/Transforms/ConvertConv2DToImg2Col.cpp
49

nit: operation

50

nit: cross-correlation

qcolombet updated this revision to Diff 498297.Feb 17 2023, 2:30 AM
qcolombet marked 10 inline comments as done.
  • Fix typos
  • Return two handles for the rewrites (one for the im2col tensor and one for the final operation)
qcolombet marked 2 inline comments as done.Feb 17 2023, 2:31 AM
qcolombet added inline comments.Feb 17 2023, 2:35 AM
mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
3070

Note: @ftynse @nicolasvasilache, unless I missed it, there's no way to report the notifyMatchFailure in the transform dialect, right now.
I think it would be interesting to have our own specialization of the IRRewriter to log these errors as part of the errors we report with emitSilenceableError and so on.

What do you think?

@nicolasvasilache on the 2 handles, I've updated the patch to do that. Let me know I return what you had in mind.

nicolasvasilache accepted this revision.Feb 17 2023, 4:38 AM

Thanks for addressing @qcolombet , I am fine with iterating from this and seeing where it goes.
I can see that it will not be in an ideal form for mapping im2col on device, I expect we will be able to evolve it iteratively.

Please wait for @mravishankar for a final confirmation

ThomasRaoux accepted this revision.Feb 17 2023, 7:41 AM
ThomasRaoux added a subscriber: ThomasRaoux.

Thanks for addressing @qcolombet , I am fine with iterating from this and seeing where it goes.
I can see that it will not be in an ideal form for mapping im2col on device, I expect we will be able to evolve it iteratively.

Please wait for @mravishankar for a final confirmation

+1 in order to do tile and fuse of generic op + conv we will need to have matching iteration space. This can be done by changing the op to use gather semantic (tensor.extract). But I think it is reasonable to do as a second step.

Seems this part of the commit message could go away?

The current plumbing is straight forward: we wrap around the greedy
pattern matcher.
Longer term, we may want to be more targeted and take as input a
linalg.conv_2d and apply the pattern only to that.
qcolombet edited the summary of this revision. (Show Details)Feb 17 2023, 9:15 AM

Seems this part of the commit message could go away?

The current plumbing is straight forward: we wrap around the greedy
pattern matcher.
Longer term, we may want to be more targeted and take as input a
linalg.conv_2d and apply the pattern only to that.

Yep, updated.

mravishankar resigned from this revision.Feb 17 2023, 7:38 PM

I am unblocking given it will be iterated on. Happy to chat offline later

This revision is now accepted and ready to land.Feb 17 2023, 7:38 PM
This revision was landed with ongoing or failed builds.Feb 23 2023, 2:29 PM
This revision was automatically updated to reflect the committed changes.