Replies: 1 comment
-
Some Additional InformationTorch provides many useful JIT passes which are helpful in rewriting in-place ops, but I have not found one that deals with the following case: The issue with the above formulation is that TorchScript produces the following IR for the forward pass: def forward(self, y):
x = torch.zeros((3, 2)).float().cuda()
idx = torch.tensor([0, 2]).int().cuda()
x[idx.long(), :] = y[idx.long(), :]
return x
# GENERATES #
%x.1 : Tensor = aten::cuda(%9)
%11 : Tensor = aten::slice(%y.1, %7, %4, %4, %7)
%13 : Tensor = aten::slice(%x.1, %7, %4, %4, %7)
%26 : Tensor = aten::index(%11, %2)
%14 : Tensor = aten::index_put_(%13, %2, %26, %6)
return (%x.1) In the above scenario, returning |
Beta Was this translation helpful? Give feedback.
-
Context
When using Torch-TensorRT to build models where the
forward
function populates a tensor on-the-fly via inplace operations, the results can sometimes differ from their TorchScript counterpart. As demonstrated in Issue #1453, creating a tensor in the forward function, populating its entries, then returning it can have unexpected results. Below is a minimal sample on a simple function:The above sample generates the following IR code, for which the problematic tensor is
%x.1
:The tensor
%x.1
is initialized as a compile-time constant tensor in Torch-TRT, and thus all "in-place" operations applied to it do not change its value. Specifically, theaten::select
andaten::copy_
operations' outputs are immediately discarded, as the original tensor (in TensorRT execution) is unchanged, whereas in TorchScript execution, these operations modify this tensor.Temporary Solutions
1. One way to circumvent this issue is to pass as an argument to the
forward
function, the tensorx
which is currently initialized in theforward
code. If the tensor is initialized outside of the function and is passed in at runtime, the inplace operations work as expected in TorchTRT, and the results agree.2. Another alternative fix is to avoid the inplace operations altogether by making copies of the tensor being assigned via the
torch.Tensor.index_select
and accompanyingaten::index_select
operators. By making a copy of the constant tensor with the desired values inserted, one is able to avoid the issue presented by using these inplace operations on constant tensors.Discussion
In the above snippet, one solution seems to be simply returning the last-modified Tensor instead of the inplace version (returning
%11
instead of%x.1
). While this can be done via a lowering pass, it will not work in the general case, as sometimes values can be assigned to a slice, and the resulting tensor output will only be a fraction of the initial tensor intended to be modified. For example, an operation such asx[:, 0] = y[:, 0]
will lead to anaten::slice
followed by anaten::index_put_
, for which the output of the latter might not be the same shape asx
.Another option could be to investigate more general graph modifications to deal with inplace operations. For example, if an inplace operation is detected on a constant tensor during the lowering phase, the graph can be modified accordingly to make a modifiable copy of the constant tensor, or potentially to eliminate the inplace calls in favor of copy-inducing calls. The inplace-call elimination is made more challenging by the use of
aten::slice
to write to a view of the initial tensor.Implementation Phases
Prototype - L
Needs further discussion on feasibility of solutions and cost/benefit of supporting inplace operations on constant Tensors.
Feedback and Suggestions
Feedback on the feasibility of the above resolution options and suggestions for alternative ideas to resolve this issue are welcome!
Beta Was this translation helpful? Give feedback.
All reactions