-
Notifications
You must be signed in to change notification settings - Fork 621
Add lowering for slice and select int #398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
A possible way to deal with the naming conflict could be to rename the argument name in the beginning of torch-mlir/python/torch_mlir/dialects/torch/importer/jit_ir/build_tools/torch_ods_gen.py Line 287 in 127c7d8
right before the ODS is generated. For example, you could do def raw_emit_op(operator: JitOperator, f: TextIO, *, traits: List[str],
has_folder: bool, has_canonicalizer: bool):
for arg in operator.arguments:
if arg['name'] == 'p':
arg['name'] = 'p0'
# rest of function |
Yeah I considered this also but I don't know if continuing to add exceptional cases there scales very prettily. Maybe its fine for now? |
Hm, yeah. To make it scale, we can just have a global list of reserved keywords, and then have something like for value in itertools.chain(operator.arguments, operator.returns):
if value['name'] in RESERVED_KEYWORDS:
value['name'] += '0'Then, every time a reserved keyword becomes a problem, we just add it to |
|
Created LLVM bug for this: https://bugs.llvm.org/show_bug.cgi?id=52387 Pending that, Ramiro's suggestion sounds good. |
This is similar to what we do in the Haskell bindings. Having such a mechanism is useful. Uniformly prefixing is another option then it is your own "namespace". |
|
The issue with the %13 = tensor.insert_slice %12 into %10[0, 0, 0] [1, 1, 2] [1, 1, 1] : tensor<?x1x2xf32> into tensor<1x1x2xf32>Since the offset is zero for all dims, the result shape is statically known, and the stride is 1, this is the same as a cast, so the folding makes sense. The problem at the moment is that there are subsequent casts that erase the folded cast knowledge, as can be seen from the IR before the folding: func @forward(%arg0: !torch.vtensor<[?,?,?],f32>) -> !torch.vtensor<[?,?,?],f32> {
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
%0 = torch_c.to_builtin_tensor %arg0 : !torch.vtensor<[?,?,?],f32> -> tensor<?x?x?xf32>
%1 = tensor.dim %0, %c1 : tensor<?x?x?xf32>
%2 = tensor.dim %0, %c2 : tensor<?x?x?xf32>
%3 = linalg.init_tensor [1, %1, %2] : tensor<1x?x?xf32>
%4 = tensor.cast %0 : tensor<?x?x?xf32> to tensor<1x?x?xf32>
%5 = tensor.insert_slice %4 into %3[0, 0, 0] [1, %1, %2] [1, 1, 1] : tensor<1x?x?xf32> into tensor<1x?x?xf32>
%6 = tensor.dim %5, %c2 : tensor<1x?x?xf32>
%7 = linalg.init_tensor [1, 1, %6] : tensor<1x1x?xf32>
%8 = tensor.cast %5 : tensor<1x?x?xf32> to tensor<1x1x?xf32>
%9 = tensor.insert_slice %8 into %7[0, 0, 0] [1, 1, %6] [1, 1, 1] : tensor<1x1x?xf32> into tensor<1x1x?xf32>
%10 = linalg.init_tensor [1, 1, 2] : tensor<1x1x2xf32>
%11 = tensor.cast %10 : tensor<1x1x2xf32> to tensor<?x1x2xf32>
%12 = tensor.cast %9 : tensor<1x1x?xf32> to tensor<?x1x2xf32>
%13 = tensor.insert_slice %12 into %10[0, 0, 0] [1, 1, 2] [1, 1, 1] : tensor<?x1x2xf32> into tensor<1x1x2xf32>
%14 = tensor.cast %13 : tensor<1x1x2xf32> to tensor<?x1x2xf32>
%15 = tensor.cast %14 : tensor<?x1x2xf32> to tensor<?x?x?xf32>
%16 = torch_c.from_builtin_tensor %15 : tensor<?x?x?xf32> -> !torch.vtensor<[?,?,?],f32>
return %16 : !torch.vtensor<[?,?,?],f32>
}This is happening because the RefineTypes is not being done correctly. At the moment all that RefineTypes is doing is assing the result shape to unknowns: torch-mlir/lib/Dialect/Torch/Transforms/RefineTypes.cpp Lines 372 to 377 in ef897db
However, If the slicer is able to determine the final shape statically, RefineTypes should also be able to do this. Once this is fixed, the result tensor should be of the correct size. However, you might run into the cast problem I stumbled upon #376 (comment) when performing e2e testing. Edit: The reason the folding into a cast is valid is because of the additional condition that the input tensor to the slice %13 = tensor.insert_slice %12 into %10[0, 0, 0] [1, 1, 2] [1, 1, 1] : tensor<?x1x2xf32> into tensor<1x1x2xf32>is compatible with the cast. |
@ramiro050 I think I fail to understand the issue. Generally speaking, the I guess I didn't get what's going wrong. The IR looks all right to me. |
|
@cathyzhyi I may be misunderstanding how the types work. Every cast I've seen done at the end of a torch-mlir/lib/Conversion/TorchToLinalg/TorchToLinalg.cpp Lines 2426 to 2427 in 42fe6a0
Which uses information from module attributes {torch.debug_module_name = "MyModule"} {
func @forward(%arg0: tensor<?x?x?xf32>) -> tensor<1x1x2xf32> {
%c2 = arith.constant 2 : index
%c1 = arith.constant 1 : index
%0 = tensor.dim %arg0, %c1 : tensor<?x?x?xf32>
%1 = tensor.dim %arg0, %c2 : tensor<?x?x?xf32>
%2 = linalg.init_tensor [1, %0, %1] : tensor<1x?x?xf32>
%3 = tensor.cast %arg0 : tensor<?x?x?xf32> to tensor<1x?x?xf32>
%4 = tensor.insert_slice %3 into %2[0, 0, 0] [1, %0, %1] [1, 1, 1] : tensor<1x?x?xf32> into tensor<1x?x?xf32>
%5 = linalg.init_tensor [1, 1, %1] : tensor<1x1x?xf32>
%6 = tensor.cast %4 : tensor<1x?x?xf32> to tensor<1x1x?xf32>
%7 = tensor.insert_slice %6 into %5[0, 0, 0] [1, 1, %1] [1, 1, 1] : tensor<1x1x?xf32> into tensor<1x1x?xf32>
%8 = tensor.cast %7 : tensor<1x1x?xf32> to tensor<1x1x2xf32>
return %8 : tensor<1x1x2xf32>
}
}
As can be seen, the result type of the function is set by the |
|
For context, I am doing the following computation: def forward(self, x):
return x[0:1, 1:2, 1:3] |
|
Yea, type conversion like this torch-mlir/lib/Conversion/TorchToLinalg/TorchToLinalg.cpp Lines 486 to 487 in 127c7d8
castOp to up cast to the type decided by RefineType. We should not depend on it for shape information.
Is the issue here the result type of the function is set by the RefinePublicReturn pass doesn't work for dynamic shape? Are you trying to make the return shape static? I think I am still not seeing the issue. |
The issue is that the final result ends up being the wrong shape, and even contains the values that should have sliced away.
while |
|
After some discussion with @ramiro050, we believe there seems to be a weird canonicalization pattern for |
|
The "p" parameter issue should be fixed in https://reviews.llvm.org/rGa7fc39f21353b657af941e84f964aa0607c92e93 Just need to update llvm. |
|
@ramiro050 @dan-garvey Just FYI, we used |
Oh, I suppose that makes a some sense. So the folding we saw is correct then. I do, however, find the documentation very misleading. From the documentation (https://mlir.llvm.org/docs/Dialects/TensorOps/#tensorinsert_slice-mlirtensorinsertsliceop)
I suppose this has to be a typo because I don't know how to interpret this other than as: |
oh, I just realized your first comment @cathyzhyi on Discourse mentions this issue with the documentation 😂 |
yea, the wording is ambiguous here. I guess it means the result of restoring the reduced-rank for the reduced rank case but not the output tensor. I will try to update the doc upstream to make it more clear. |
5784843 to
65cc5f9
Compare
2ac3c33 to
e1b5a32
Compare
4cf5547 to
c868e89
Compare
e1b5a32 to
611f411
Compare
|
@dan-garvey this contains multiple ops. The slice and select are related but |
2e4cfc5 to
ec404ca
Compare
dd0953a to
703502d
Compare
703502d to
b6cc375
Compare
| SmallVector<Value> inputShape = getTensorSizes(rewriter, loc, input); | ||
| Value dimSize = inputShape[dim]; | ||
|
|
||
| auto adjustStartOrEnd = [](Location loc, Value dimSize, Value &startOrEnd, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using [&] could capture the variable from context and Location loc, Value dimSize, ConversionPatternRewriter &rewriter can be used directly rather than passing as arguments. The logic to check NoneType can also be wrapped into the lambda. The lambda become
auto adjustStartOrEnd = [&](Value startOrEndTorch, Value startOrEndBuiltIn, Value valueForNone) {
if (startOrEndTorchType.getType().isa<NoneType>())
return valueForNone;
...
}
b6cc375 to
4c223c9
Compare
cathyzhyi
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Thanks!!
| # ============================================================================== | ||
|
|
||
| # This Test currently xfails due to https://github.com/llvm/torch-mlir/issues/448 | ||
| class SliceStartEqEnd_Module(torch.nn.Module): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SliceStartEqEnd_Module => SliceStartEqEndModule
4c223c9 to
a4f7dcf
Compare
a4f7dcf to
b15324b
Compare
|
Looks like the DecomposeAtenSelectIntOp led to a bug in distilgpt2. The gdb trace is in the comment. @dan-garvey |
Probably should have just kept dropout separate. One issue with dropout is that it has an argument called p, which is the probability an element is zero'd. This has a naming conflict the the asm printer p. I'm not sure what the best way to avoid this is, and am open to suggestion. Currently to work I just edited the generated cpp file, but that obviously isn't upstreamable.
I've tried so far to model slice in a way that it easily extends to other slice like ops. My plan is to continue to generalize things out of the
if (auto SliceTensor = dyn_cast<AtenSliceTensorOp>(op))statement.There is currently an issue with AtenSliceTensor when there is a start and end for each dimension. For a reason I have yet to determine, the final dimension always maintains the shape of the original tensor instead of being updated to the slice size. In the IR, it actually correctly determines the final dim, but somehow loses track of the initial dim:
I'm not too familiar with how the canonicalizer works, so I'm looking into that.
slice_mlir