-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
[Relax] Implement relax.op.view #16955
Conversation
By line count, this PR looks bigger than it actually is. Because this functionality can , there's a lot more error checking than usual, and a lot more test cases to validate those error-checking paths. Breaking down the changes in this commit, the majority are test cases, and the majority of what remain are error-checking paths.
|
This commit implements `relax.op.view` (`R.view` in TVMScript) to produce a view into an existing array. This returned view shares the same backing allocation as the existing array. Because `R.view` comes with potential trade-offs; such as increased memory footprint, performance cost to apply a non-zero `DLTensor::byte_offset`, and potential misalignment for vector operators; this PR does not use `R.view` apart from unit tests. Applications of `R.view`, either for specific compute kernels or in optimization passes, is instead kept for follow-up PRs.
0cb58ce
to
ed4fd50
Compare
src/relax/op/tensor/view.cc
Outdated
} | ||
|
||
StructInfoDeriveFunc infer_sinfo_env_func; | ||
infer_sinfo_env_func = EnvFunc::Get("tvm.relax.struct_info.infer_view_sinfo"); |
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.
Why does this need to be a packed func? Can't we use the C++ function directly?
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.
If we want to define the StructInfo for the generated Call
node, we could call the C++ function directly. Ideally, though, if the arguments change due to some downstream transform, the shape inference should be repeated with the new argument. For that
- Using an operator's
FInferStructInfo
function. This only applies totvm.ir.Op
instances, and we've just removed that as part ofLegalizeOps
. - Using the
params
andret
fields from theFuncStructInfo
. This works for static cases, and most dynamic shapes, but doesn't support inferring the output shape based on aShapeExpr
argument. - Using
FuncStructInfo::OpaqueFunc
with a derivation func. This is the most general method, and essentially lets you pack aFInferStructInfo
into aFuncStructInfo
.
The third option doesn't come up very often, and I could only find one previous location where this functionality is used. (Previous usage is here, which defines the use of CallNode::sinfo_args
as the default inferred struct info for external functions.)
Just want to note here. Having view operation can in general cause problems mainly because most ops(including generated and external ones) assumes Ideally we would like to ensure such assumption to hold. This being said there are some needs in slicing out the arrays. e.g. in the case of LoRA elements. There are a few ways to go with this:
|
So long as the operations assert that the element offset is zero when this assumption is being made, this makes sense. This is what we do in For external operations that accept an aligned pointer to data, I like your suggestion of ensuring that we provide aligned data. My plan was to only introduce views that maintain the same alignment that is provided by existing allocations. For external operations that accept a
To be clear, do you mean Having the dedicated operation for it would also work well for dynamically-shaped arguments. In those cases, we wouldn't know until runtime whether the operation requires a copy or not in order to provide an aligned argument.
I agree with aiming to have views be fused with later operations where possible, though I'd add that this is not LoRA-specific functionality. Anywhere that
I think the only assumption it makes is that a platform supports casting of pointers. Regarding names, I agree that |
- Rename `R.view` to `R.memory.view` - Rename `relax.op.view` to `relax.op.memory.view`
Changes have been made as requested, ready for re-review. |
|
Having Any other concerns? I think this PR is ready to merge. |
dismissing my previous requests as they are addressed
Thank you! my previous comments are addressed. Unfortunately i didn't get a chance to do a thourough read, would be good to get review from another person. So i just dissmissed my previous comment |
Sounds good, and thank you on the feedback! |
python/tvm/relax/op/memory/view.py
Outdated
# specific language governing permissions and limitations | ||
# under the License. | ||
|
||
"""Operations that act on the DLTensor container """ |
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.
Need update here
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.
Sounds good, and updated.
python/tvm/relax/op/memory/view.py
Outdated
dtype: Optional[Expr] = None, | ||
relative_byte_offset: Optional[Expr] = None, | ||
) -> Expr: | ||
"""Broadcasts a tensor to a specified shape. |
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.
Need update here
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.
Thank you on the catch, and updated.
@@ -296,13 +298,17 @@ class CallableProxy(StructInfoProxy): | |||
purity : bool | |||
Whether the callable is pure. | |||
|
|||
derive_func: Optional[Union[str, tvm.ir.EnvFunc]] | |||
The derivation function for the outputq |
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.
Typo outputq
?
And what is a derivation function?
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.
Typo, updated to output
.
The derivation function is equivalent to FInferStructInfo
set for relax operations, but can be applied to an arbitrary function. It can be used in cases where a PackedFunc may be called, and the output StructInfo
should be derived from the input arguments, rather than taken from sinfo_args
. This functionality has existed in the C++ API for a while, but it looks like this is the first time it's been exposed through the Python API, so I fleshed out the description here.
@tvm-bot rerun |
… R.view (#17145) Previously, `R.view` was legalized to extern call to `runtime.TVMArrayCreateView` during `LegalizeOps`. This call to extern func can't be properly handled by `StaticBlockPlanMemory` because it assumes the extern func does not retain the input buffer. Extern func returning a view of the input would break the ref count of the buffer. This PR defers the legalization of `R.view` so that it can be explicitly handled by memory planning. A new op `R.ensure_aligned` is added as discussed in #16955
This commit implements
relax.op.view
(R.view
in TVMScript) to produce a view into an existing array. This returned view shares the same backing allocation as the existing array.Because
R.view
comes with potential trade-offs; such as increased memory footprint, performance cost to apply a non-zeroDLTensor::byte_offset
, and potential misalignment for vector operators; this PR does not useR.view
apart from unit tests. Applications ofR.view
, either for specific compute kernels or in optimization passes, is instead kept for follow-up PRs.