Skip to content

Commit f38fcac

Browse files
authored
[TorchOnnxToTorch] Lower ReverseSequence using torch.prim.Loop (#4739)
Updated the ONNX `ReverseSequence` conversion to use a runtime `torch.prim.Loop` over the batch dimension. The previous implementation statically unrolled the operation based off the compile-time batch size, so it failed to apply the operation for dynamic batch dimensions. The new implementation obtains the batch size at runtime and iterates over each batch element using `torch.prim.Loop`. It emits the same set of operations to reverse the selected portion and can now support both static and dynamic batch dimensions. Tests: - Updated the existing batch-axis and time-axis `ReverseSequence` tests to check for the new operations - Added a regression test in `simple_ops_q_to_z.mlir` for a dynamic batch dimension
1 parent bd16df2 commit f38fcac

2 files changed

Lines changed: 104 additions & 112 deletions

File tree

lib/Conversion/TorchOnnxToTorch/DefaultDomainQtoZ.cpp

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3999,31 +3999,52 @@ void mlir::torch::onnx_c::populateDefaultDomainQtoZ(
39993999
flipShape[timeAxis] = Torch::kUnknownSize;
40004000
auto flipType =
40014001
rewriter.getType<Torch::ValueTensorType>(flipShape, dtype);
4002-
auto scalarTensorType = rewriter.getType<Torch::ValueTensorType>(
4003-
ArrayRef<int64_t>{1}, rewriter.getIntegerType(64, /*signed*/ 1));
4002+
// iterate over the batch dimension at runtime
4003+
Value batchSize = Torch::AtenSizeIntOp::create(
4004+
rewriter, binder.getLoc(), rewriter.getType<Torch::IntType>(),
4005+
input, batchAxisVal);
40044006

4005-
for (int i = 0; i < inputShape[batchAxis]; i++) {
4006-
// slice i iterating on batch axis
4007-
Value k = Torch::ConstantIntOp::create(rewriter, binder.getLoc(),
4008-
rewriter.getI64IntegerAttr(i));
4007+
Value loopConditionTrue = Torch::ConstantBoolOp::create(
4008+
rewriter, binder.getLoc(), rewriter.getBoolAttr(true));
4009+
Type loopIndexType = rewriter.getType<Torch::IntType>();
4010+
auto sequenceLensTy =
4011+
cast<Torch::ValueTensorType>(sequenceLens.getType());
4012+
auto sequenceLengthTensorType =
4013+
rewriter.getType<Torch::ValueTensorType>(ArrayRef<int64_t>{},
4014+
sequenceLensTy.getDtype());
4015+
4016+
auto loop = Torch::PrimLoopOp::create(
4017+
rewriter, binder.getLoc(), TypeRange({resultType}), batchSize,
4018+
loopConditionTrue, ValueRange({input}));
4019+
{
4020+
PatternRewriter::InsertionGuard guard(rewriter);
4021+
Block *loopBody =
4022+
rewriter.createBlock(&loop.getRegion(), loop.getRegion().begin(),
4023+
TypeRange({loopIndexType, resultType}),
4024+
{binder.getLoc(), binder.getLoc()});
4025+
4026+
Value k = loopBody->getArgument(0);
4027+
Value currInput = loopBody->getArgument(1);
4028+
4029+
// slice k iterating on batch axis
40094030
Value end =
40104031
Torch::AtenAddIntOp::create(rewriter, binder.getLoc(), k, cstOne);
4032+
40114033
Value sliceBatch = Torch::AtenSliceTensorOp::create(
4012-
rewriter, binder.getLoc(), sliceType, input, batchAxisVal, k, end,
4013-
cstOne);
4034+
rewriter, binder.getLoc(), sliceType, currInput, batchAxisVal, k,
4035+
end, cstOne);
40144036

40154037
// get sequence length and slice the reversing part
4016-
Value kTensor = Torch::PrimNumToTensorScalarOp::create(
4017-
rewriter, binder.getLoc(), scalarTensorType, k);
4018-
Value sel = Torch::AtenIndexSelectOp::create(
4019-
rewriter, binder.getLoc(), scalarTensorType, sequenceLens,
4020-
cstZero, kTensor);
4038+
Value sel = Torch::AtenSelectIntOp::create(rewriter, binder.getLoc(),
4039+
sequenceLengthTensorType,
4040+
sequenceLens, cstZero, k);
40214041
Value len = Torch::AtenItemOp::create(
40224042
rewriter, binder.getLoc(), rewriter.getType<Torch::IntType>(),
40234043
sel);
40244044
Value sliceTime = Torch::AtenSliceTensorOp::create(
40254045
rewriter, binder.getLoc(), flipType, sliceBatch, timeAxisVal,
40264046
cstZero, len, cstOne);
4047+
40274048
// flip the sliced reversing tensor
40284049
Value dims = Torch::PrimListConstructOp::create(
40294050
rewriter, binder.getLoc(),
@@ -4036,15 +4057,17 @@ void mlir::torch::onnx_c::populateDefaultDomainQtoZ(
40364057
// embeds the reversed tensor to the input
40374058
Value embedTime = Torch::AtenSliceScatterOp::create(
40384059
rewriter, binder.getLoc(), sliceType, sliceBatch, flip,
4039-
timeAxisVal,
4040-
/*start=*/cstZero, /*end=*/len, /*step=*/cstOne);
4041-
input = Torch::AtenSliceScatterOp::create(
4042-
rewriter, binder.getLoc(), resultType, input, embedTime,
4043-
batchAxisVal,
4044-
/*start=*/k, /*end=*/end, /*step=*/cstOne);
4060+
timeAxisVal, /*start=*/cstZero, /*end=*/len, /*step=*/cstOne);
4061+
Value updatedInput = Torch::AtenSliceScatterOp::create(
4062+
rewriter, binder.getLoc(), resultType, currInput, embedTime,
4063+
batchAxisVal, /*start=*/k, /*end=*/end, /*step=*/cstOne);
4064+
4065+
Torch::PrimLoopConditionOp::create(rewriter, binder.getLoc(),
4066+
loopConditionTrue,
4067+
ValueRange({updatedInput}));
40454068
}
40464069

4047-
rewriter.replaceOp(binder.op, input);
4070+
rewriter.replaceOp(binder.op, loop.getResult(0));
40484071
return success();
40494072
});
40504073
patterns.onOp(

0 commit comments

Comments
 (0)