Skip to content

[Relax] Implement operators to read runtime DLTensor* information - #16563

Merged
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops
Feb 20, 2024
Merged

[Relax] Implement operators to read runtime DLTensor* information#16563
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops

Conversation

@Lunderberg

Copy link
Copy Markdown
Contributor

Relax is capable of expressing tensors whose element type is unknown. However, these must typically be replaced with a known dtype prior to compilation, as most operators require known data types prior to legalization. This can be done by using a relax::MatchCast node, such as accepting a parameter arg: R.Tensor([16,16]), then defining the dtype using R.match_cast(arg, R.Tensor([16,16],'float16')).

However, using a R.match_cast node requires knowing which data type should be used in the new R.Tensor, and raises an error for an incorrect data type. If an argument may be one of two distinct data types, R.match_cast cannot be used to check which data type is in use.

This commit adds Relax operators to read the runtime values of a DLTensor* argument. These can be be used to normalize arguments prior to a compute step. For example, pre-processing a model weight that may be provided in either float16 or bfloat16 format.

Relax is capable of expressing tensors whose element type is unknown.
However, these must typically be replaced with a known dtype prior to
compilation, as most operators require known data types prior to
legalization. This can be done by using a `relax::MatchCast` node,
such as accepting a parameter `arg: R.Tensor([16,16])`, then defining
the dtype using `R.match_cast(arg, R.Tensor([16,16],'float16'))`.
However, using a `R.match_cast` node requires knowing which data type
should be used in the new `R.Tensor`, and raises an error for an
incorrect data type. If an argument may be one of two distinct data
types, `R.match_cast` cannot be used to check which data type is in
use.
This commit adds Relax operators to read the runtime values of a
`DLTensor*` argument. These can be be used to normalize arguments
prior to a compute step. For example, pre-processing a model weight
that may be provided in either `float16` or `bfloat16` format.

@slyubomirskyslyubomirsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Comment threadpython/tvm/relax/expr.py Outdated

Used for early checks in `expr.dtype` and `expr.shape`
accessors. While invalid usage would cause errors to be
raised durin shape inference, an earlier check makes it easier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raiseddurinshapeinference, anearliercheckmakesiteasier
raisedduringshapeinference, anearliercheckmakesiteasier

typo

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and fixed

Comment on lines +287 to +288
Exposes accessors for `DLDataType` fields `type_code`, `lanes`,
and `bits` within a `DLTensor::dtype`. Accessing these fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good to have. Offset might also be useful to add, as it might help for memory reuse.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. At the moment, I stuck with the values that have a direct presence elsewhere in Relax, but I agree that it would be good to be able to extract any of the DLTensor* fields.

Comment threadsrc/relax/op/tensor/unpack.cc Outdated
*/

/*!
* \file unpack.cc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "unpack" is the best name. Perhaps "accessors" or "runtime_accessors" could be a little more descriptive? I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about relax.inspect(as a sub namespace for the ops)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like relax.inspect quite a bit, and will update the tensors to that namespace.

Comment on lines +225 to +227
// TODO(Lunderberg): Make a new operator attribute
// `.set_attr<Bool>("DataDependent")`, rather than relying on
// the name of the operator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, probably should be a separate PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The note is more so that it has a record somewhere, but it would be enough of a change that it should be part of a separate PR. As it was, I wanted to make as few changes to LegalizeOps as possible in this PR.

Comment on lines +192 to +204
// Improve this fallback case, as failure to legalize can
// produce unexpected errors during CodeGenVM. This could
// be done by having `R.Tensor(ndim=2)` be syntactic sugar
// for `R.Tensor(shape=[m, n])`, where `m` and `n` are new
// shape variables. This would allow legalization into
// dynamic TIR PrimFuncs.
//
// This fallback would only be applicable for cases where
// both the dtype and the dimensionality are known. While
// Relax can express a tensor with unknown dtype and
// dimensionality as `TensorStructInfo(DataType::Void(),
// kUnknownNDim)`, TIR cannot express unknown dtype or
// unknown dimensionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. This could be done by inserting a MatchCast that introduces the new vars. Perhaps this should be filed as an issue rather than made a long comment.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, though I haven't had time to flesh out the idea yet. This would be part of a general cleanup I'd propose for the StructInfo interactions:

  • Remove the Optional<Expr> shape and int ndim in TensorStructInfo. Instead, have Optional<ShapeStructInfo>.
  • Remove the ndim field from ShapeStructInfo. Instead, the ndim is unknown when Optional<Array<PrimExpr>> is NullOpt.
  • If the dimensionality of a ShapeStructInfo is known, every dimension must have an associated PrimExpr. The constructor that accepts ndim initializes fresh TIR variables to represent the unknown size.

)

@property
def dtype(self) -> "_DLTensorDTypeProxy":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the return type have to be in quotes? I assume it has to do with the property decorator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the order of definitions in the file. Function annotations are evaluated when the class is being defined. Since the _DLTensorDTypeProxy class is defined lower in the file, the type annotations are provided as a string, rather than as a class object.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Thank you! I really like polishing up the interface to be as clean as possible. (For my own sake if nothing else, as I am liable to forget a builtin-function name, but am much less likely to forget obj.dtype.)

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Prior to LegalizeOps, this is implicitly done by the FNormalize implementation for each operator. After LegalizeOps, not so much. While the FoldConstant pass can compile/run TIR functions if their arguments are known, there isn't a good way to indicate that a TIR function only requires the DLTensor struct, and not the data itself.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

All CI tests passing, and thank you for the review @slyubomirsky ! I'll follow up with another PR to add inspection of the remainder of the DLTensor* fields.

@Lunderberg
Lunderberg merged commit b218557 into apache:mainFeb 20, 2024
@Lunderberg
Lunderberg deleted the relax_unpack_ops branch February 20, 2024 20:59
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 14, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 15, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 18, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit that referenced this pull request Mar 26, 2024
…16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to #16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
…pache#16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Lunderberg@tqchen@slyubomirsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
[Relax] Implement operators to read runtime DLTensor* information by Lunderberg · Pull Request #16563 · apache/tvm · GitHub
Skip to content

[Relax] Implement operators to read runtime DLTensor* information - #16563

Merged
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops
Feb 20, 2024
Merged

[Relax] Implement operators to read runtime DLTensor* information#16563
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops

Conversation

@Lunderberg

Copy link
Copy Markdown
Contributor

Relax is capable of expressing tensors whose element type is unknown. However, these must typically be replaced with a known dtype prior to compilation, as most operators require known data types prior to legalization. This can be done by using a relax::MatchCast node, such as accepting a parameter arg: R.Tensor([16,16]), then defining the dtype using R.match_cast(arg, R.Tensor([16,16],'float16')).

However, using a R.match_cast node requires knowing which data type should be used in the new R.Tensor, and raises an error for an incorrect data type. If an argument may be one of two distinct data types, R.match_cast cannot be used to check which data type is in use.

This commit adds Relax operators to read the runtime values of a DLTensor* argument. These can be be used to normalize arguments prior to a compute step. For example, pre-processing a model weight that may be provided in either float16 or bfloat16 format.

Relax is capable of expressing tensors whose element type is unknown.
However, these must typically be replaced with a known dtype prior to
compilation, as most operators require known data types prior to
legalization. This can be done by using a `relax::MatchCast` node,
such as accepting a parameter `arg: R.Tensor([16,16])`, then defining
the dtype using `R.match_cast(arg, R.Tensor([16,16],'float16'))`.
However, using a `R.match_cast` node requires knowing which data type
should be used in the new `R.Tensor`, and raises an error for an
incorrect data type. If an argument may be one of two distinct data
types, `R.match_cast` cannot be used to check which data type is in
use.
This commit adds Relax operators to read the runtime values of a
`DLTensor*` argument. These can be be used to normalize arguments
prior to a compute step. For example, pre-processing a model weight
that may be provided in either `float16` or `bfloat16` format.

@slyubomirskyslyubomirsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Comment threadpython/tvm/relax/expr.py Outdated

Used for early checks in `expr.dtype` and `expr.shape`
accessors. While invalid usage would cause errors to be
raised durin shape inference, an earlier check makes it easier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raiseddurinshapeinference, anearliercheckmakesiteasier
raisedduringshapeinference, anearliercheckmakesiteasier

typo

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and fixed

Comment on lines +287 to +288
Exposes accessors for `DLDataType` fields `type_code`, `lanes`,
and `bits` within a `DLTensor::dtype`. Accessing these fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good to have. Offset might also be useful to add, as it might help for memory reuse.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. At the moment, I stuck with the values that have a direct presence elsewhere in Relax, but I agree that it would be good to be able to extract any of the DLTensor* fields.

Comment threadsrc/relax/op/tensor/unpack.cc Outdated
*/

/*!
* \file unpack.cc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "unpack" is the best name. Perhaps "accessors" or "runtime_accessors" could be a little more descriptive? I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about relax.inspect(as a sub namespace for the ops)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like relax.inspect quite a bit, and will update the tensors to that namespace.

Comment on lines +225 to +227
// TODO(Lunderberg): Make a new operator attribute
// `.set_attr<Bool>("DataDependent")`, rather than relying on
// the name of the operator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, probably should be a separate PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The note is more so that it has a record somewhere, but it would be enough of a change that it should be part of a separate PR. As it was, I wanted to make as few changes to LegalizeOps as possible in this PR.

Comment on lines +192 to +204
// Improve this fallback case, as failure to legalize can
// produce unexpected errors during CodeGenVM. This could
// be done by having `R.Tensor(ndim=2)` be syntactic sugar
// for `R.Tensor(shape=[m, n])`, where `m` and `n` are new
// shape variables. This would allow legalization into
// dynamic TIR PrimFuncs.
//
// This fallback would only be applicable for cases where
// both the dtype and the dimensionality are known. While
// Relax can express a tensor with unknown dtype and
// dimensionality as `TensorStructInfo(DataType::Void(),
// kUnknownNDim)`, TIR cannot express unknown dtype or
// unknown dimensionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. This could be done by inserting a MatchCast that introduces the new vars. Perhaps this should be filed as an issue rather than made a long comment.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, though I haven't had time to flesh out the idea yet. This would be part of a general cleanup I'd propose for the StructInfo interactions:

  • Remove the Optional<Expr> shape and int ndim in TensorStructInfo. Instead, have Optional<ShapeStructInfo>.
  • Remove the ndim field from ShapeStructInfo. Instead, the ndim is unknown when Optional<Array<PrimExpr>> is NullOpt.
  • If the dimensionality of a ShapeStructInfo is known, every dimension must have an associated PrimExpr. The constructor that accepts ndim initializes fresh TIR variables to represent the unknown size.

)

@property
def dtype(self) -> "_DLTensorDTypeProxy":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the return type have to be in quotes? I assume it has to do with the property decorator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the order of definitions in the file. Function annotations are evaluated when the class is being defined. Since the _DLTensorDTypeProxy class is defined lower in the file, the type annotations are provided as a string, rather than as a class object.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Thank you! I really like polishing up the interface to be as clean as possible. (For my own sake if nothing else, as I am liable to forget a builtin-function name, but am much less likely to forget obj.dtype.)

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Prior to LegalizeOps, this is implicitly done by the FNormalize implementation for each operator. After LegalizeOps, not so much. While the FoldConstant pass can compile/run TIR functions if their arguments are known, there isn't a good way to indicate that a TIR function only requires the DLTensor struct, and not the data itself.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

All CI tests passing, and thank you for the review @slyubomirsky ! I'll follow up with another PR to add inspection of the remainder of the DLTensor* fields.

@Lunderberg
Lunderberg merged commit b218557 into apache:mainFeb 20, 2024
@Lunderberg
Lunderberg deleted the relax_unpack_ops branch February 20, 2024 20:59
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 14, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 15, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 18, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit that referenced this pull request Mar 26, 2024
…16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to #16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
…pache#16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Lunderberg@tqchen@slyubomirsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [Relax] Implement operators to read runtime DLTensor* information by Lunderberg · Pull Request #16563 · apache/tvm · GitHub
Skip to content

[Relax] Implement operators to read runtime DLTensor* information - #16563

Merged
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops
Feb 20, 2024
Merged

[Relax] Implement operators to read runtime DLTensor* information#16563
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops

Conversation

@Lunderberg

Copy link
Copy Markdown
Contributor

Relax is capable of expressing tensors whose element type is unknown. However, these must typically be replaced with a known dtype prior to compilation, as most operators require known data types prior to legalization. This can be done by using a relax::MatchCast node, such as accepting a parameter arg: R.Tensor([16,16]), then defining the dtype using R.match_cast(arg, R.Tensor([16,16],'float16')).

However, using a R.match_cast node requires knowing which data type should be used in the new R.Tensor, and raises an error for an incorrect data type. If an argument may be one of two distinct data types, R.match_cast cannot be used to check which data type is in use.

This commit adds Relax operators to read the runtime values of a DLTensor* argument. These can be be used to normalize arguments prior to a compute step. For example, pre-processing a model weight that may be provided in either float16 or bfloat16 format.

Relax is capable of expressing tensors whose element type is unknown.
However, these must typically be replaced with a known dtype prior to
compilation, as most operators require known data types prior to
legalization. This can be done by using a `relax::MatchCast` node,
such as accepting a parameter `arg: R.Tensor([16,16])`, then defining
the dtype using `R.match_cast(arg, R.Tensor([16,16],'float16'))`.
However, using a `R.match_cast` node requires knowing which data type
should be used in the new `R.Tensor`, and raises an error for an
incorrect data type. If an argument may be one of two distinct data
types, `R.match_cast` cannot be used to check which data type is in
use.
This commit adds Relax operators to read the runtime values of a
`DLTensor*` argument. These can be be used to normalize arguments
prior to a compute step. For example, pre-processing a model weight
that may be provided in either `float16` or `bfloat16` format.

@slyubomirskyslyubomirsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Comment threadpython/tvm/relax/expr.py Outdated

Used for early checks in `expr.dtype` and `expr.shape`
accessors. While invalid usage would cause errors to be
raised durin shape inference, an earlier check makes it easier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raiseddurinshapeinference, anearliercheckmakesiteasier
raisedduringshapeinference, anearliercheckmakesiteasier

typo

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and fixed

Comment on lines +287 to +288
Exposes accessors for `DLDataType` fields `type_code`, `lanes`,
and `bits` within a `DLTensor::dtype`. Accessing these fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good to have. Offset might also be useful to add, as it might help for memory reuse.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. At the moment, I stuck with the values that have a direct presence elsewhere in Relax, but I agree that it would be good to be able to extract any of the DLTensor* fields.

Comment threadsrc/relax/op/tensor/unpack.cc Outdated
*/

/*!
* \file unpack.cc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "unpack" is the best name. Perhaps "accessors" or "runtime_accessors" could be a little more descriptive? I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about relax.inspect(as a sub namespace for the ops)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like relax.inspect quite a bit, and will update the tensors to that namespace.

Comment on lines +225 to +227
// TODO(Lunderberg): Make a new operator attribute
// `.set_attr<Bool>("DataDependent")`, rather than relying on
// the name of the operator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, probably should be a separate PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The note is more so that it has a record somewhere, but it would be enough of a change that it should be part of a separate PR. As it was, I wanted to make as few changes to LegalizeOps as possible in this PR.

Comment on lines +192 to +204
// Improve this fallback case, as failure to legalize can
// produce unexpected errors during CodeGenVM. This could
// be done by having `R.Tensor(ndim=2)` be syntactic sugar
// for `R.Tensor(shape=[m, n])`, where `m` and `n` are new
// shape variables. This would allow legalization into
// dynamic TIR PrimFuncs.
//
// This fallback would only be applicable for cases where
// both the dtype and the dimensionality are known. While
// Relax can express a tensor with unknown dtype and
// dimensionality as `TensorStructInfo(DataType::Void(),
// kUnknownNDim)`, TIR cannot express unknown dtype or
// unknown dimensionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. This could be done by inserting a MatchCast that introduces the new vars. Perhaps this should be filed as an issue rather than made a long comment.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, though I haven't had time to flesh out the idea yet. This would be part of a general cleanup I'd propose for the StructInfo interactions:

  • Remove the Optional<Expr> shape and int ndim in TensorStructInfo. Instead, have Optional<ShapeStructInfo>.
  • Remove the ndim field from ShapeStructInfo. Instead, the ndim is unknown when Optional<Array<PrimExpr>> is NullOpt.
  • If the dimensionality of a ShapeStructInfo is known, every dimension must have an associated PrimExpr. The constructor that accepts ndim initializes fresh TIR variables to represent the unknown size.

)

@property
def dtype(self) -> "_DLTensorDTypeProxy":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the return type have to be in quotes? I assume it has to do with the property decorator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the order of definitions in the file. Function annotations are evaluated when the class is being defined. Since the _DLTensorDTypeProxy class is defined lower in the file, the type annotations are provided as a string, rather than as a class object.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Thank you! I really like polishing up the interface to be as clean as possible. (For my own sake if nothing else, as I am liable to forget a builtin-function name, but am much less likely to forget obj.dtype.)

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Prior to LegalizeOps, this is implicitly done by the FNormalize implementation for each operator. After LegalizeOps, not so much. While the FoldConstant pass can compile/run TIR functions if their arguments are known, there isn't a good way to indicate that a TIR function only requires the DLTensor struct, and not the data itself.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

All CI tests passing, and thank you for the review @slyubomirsky ! I'll follow up with another PR to add inspection of the remainder of the DLTensor* fields.

@Lunderberg
Lunderberg merged commit b218557 into apache:mainFeb 20, 2024
@Lunderberg
Lunderberg deleted the relax_unpack_ops branch February 20, 2024 20:59
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 14, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 15, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 18, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit that referenced this pull request Mar 26, 2024
…16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to #16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
…pache#16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Lunderberg@tqchen@slyubomirsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [Relax] Implement operators to read runtime DLTensor* information by Lunderberg · Pull Request #16563 · apache/tvm · GitHub
Skip to content

[Relax] Implement operators to read runtime DLTensor* information - #16563

Merged
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops
Feb 20, 2024
Merged

[Relax] Implement operators to read runtime DLTensor* information#16563
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops

Conversation

@Lunderberg

Copy link
Copy Markdown
Contributor

Relax is capable of expressing tensors whose element type is unknown. However, these must typically be replaced with a known dtype prior to compilation, as most operators require known data types prior to legalization. This can be done by using a relax::MatchCast node, such as accepting a parameter arg: R.Tensor([16,16]), then defining the dtype using R.match_cast(arg, R.Tensor([16,16],'float16')).

However, using a R.match_cast node requires knowing which data type should be used in the new R.Tensor, and raises an error for an incorrect data type. If an argument may be one of two distinct data types, R.match_cast cannot be used to check which data type is in use.

This commit adds Relax operators to read the runtime values of a DLTensor* argument. These can be be used to normalize arguments prior to a compute step. For example, pre-processing a model weight that may be provided in either float16 or bfloat16 format.

Relax is capable of expressing tensors whose element type is unknown.
However, these must typically be replaced with a known dtype prior to
compilation, as most operators require known data types prior to
legalization. This can be done by using a `relax::MatchCast` node,
such as accepting a parameter `arg: R.Tensor([16,16])`, then defining
the dtype using `R.match_cast(arg, R.Tensor([16,16],'float16'))`.
However, using a `R.match_cast` node requires knowing which data type
should be used in the new `R.Tensor`, and raises an error for an
incorrect data type. If an argument may be one of two distinct data
types, `R.match_cast` cannot be used to check which data type is in
use.
This commit adds Relax operators to read the runtime values of a
`DLTensor*` argument. These can be be used to normalize arguments
prior to a compute step. For example, pre-processing a model weight
that may be provided in either `float16` or `bfloat16` format.

@slyubomirskyslyubomirsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Comment threadpython/tvm/relax/expr.py Outdated

Used for early checks in `expr.dtype` and `expr.shape`
accessors. While invalid usage would cause errors to be
raised durin shape inference, an earlier check makes it easier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raiseddurinshapeinference, anearliercheckmakesiteasier
raisedduringshapeinference, anearliercheckmakesiteasier

typo

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and fixed

Comment on lines +287 to +288
Exposes accessors for `DLDataType` fields `type_code`, `lanes`,
and `bits` within a `DLTensor::dtype`. Accessing these fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good to have. Offset might also be useful to add, as it might help for memory reuse.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. At the moment, I stuck with the values that have a direct presence elsewhere in Relax, but I agree that it would be good to be able to extract any of the DLTensor* fields.

Comment threadsrc/relax/op/tensor/unpack.cc Outdated
*/

/*!
* \file unpack.cc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "unpack" is the best name. Perhaps "accessors" or "runtime_accessors" could be a little more descriptive? I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about relax.inspect(as a sub namespace for the ops)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like relax.inspect quite a bit, and will update the tensors to that namespace.

Comment on lines +225 to +227
// TODO(Lunderberg): Make a new operator attribute
// `.set_attr<Bool>("DataDependent")`, rather than relying on
// the name of the operator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, probably should be a separate PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The note is more so that it has a record somewhere, but it would be enough of a change that it should be part of a separate PR. As it was, I wanted to make as few changes to LegalizeOps as possible in this PR.

Comment on lines +192 to +204
// Improve this fallback case, as failure to legalize can
// produce unexpected errors during CodeGenVM. This could
// be done by having `R.Tensor(ndim=2)` be syntactic sugar
// for `R.Tensor(shape=[m, n])`, where `m` and `n` are new
// shape variables. This would allow legalization into
// dynamic TIR PrimFuncs.
//
// This fallback would only be applicable for cases where
// both the dtype and the dimensionality are known. While
// Relax can express a tensor with unknown dtype and
// dimensionality as `TensorStructInfo(DataType::Void(),
// kUnknownNDim)`, TIR cannot express unknown dtype or
// unknown dimensionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. This could be done by inserting a MatchCast that introduces the new vars. Perhaps this should be filed as an issue rather than made a long comment.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, though I haven't had time to flesh out the idea yet. This would be part of a general cleanup I'd propose for the StructInfo interactions:

  • Remove the Optional<Expr> shape and int ndim in TensorStructInfo. Instead, have Optional<ShapeStructInfo>.
  • Remove the ndim field from ShapeStructInfo. Instead, the ndim is unknown when Optional<Array<PrimExpr>> is NullOpt.
  • If the dimensionality of a ShapeStructInfo is known, every dimension must have an associated PrimExpr. The constructor that accepts ndim initializes fresh TIR variables to represent the unknown size.

)

@property
def dtype(self) -> "_DLTensorDTypeProxy":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the return type have to be in quotes? I assume it has to do with the property decorator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the order of definitions in the file. Function annotations are evaluated when the class is being defined. Since the _DLTensorDTypeProxy class is defined lower in the file, the type annotations are provided as a string, rather than as a class object.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Thank you! I really like polishing up the interface to be as clean as possible. (For my own sake if nothing else, as I am liable to forget a builtin-function name, but am much less likely to forget obj.dtype.)

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Prior to LegalizeOps, this is implicitly done by the FNormalize implementation for each operator. After LegalizeOps, not so much. While the FoldConstant pass can compile/run TIR functions if their arguments are known, there isn't a good way to indicate that a TIR function only requires the DLTensor struct, and not the data itself.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

All CI tests passing, and thank you for the review @slyubomirsky ! I'll follow up with another PR to add inspection of the remainder of the DLTensor* fields.

@Lunderberg
Lunderberg merged commit b218557 into apache:mainFeb 20, 2024
@Lunderberg
Lunderberg deleted the relax_unpack_ops branch February 20, 2024 20:59
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 14, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 15, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 18, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit that referenced this pull request Mar 26, 2024
…16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to #16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
…pache#16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Lunderberg@tqchen@slyubomirsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [Relax] Implement operators to read runtime DLTensor* information by Lunderberg · Pull Request #16563 · apache/tvm · GitHub
Skip to content

[Relax] Implement operators to read runtime DLTensor* information - #16563

Merged
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops
Feb 20, 2024
Merged

[Relax] Implement operators to read runtime DLTensor* information#16563
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops

Conversation

@Lunderberg

Copy link
Copy Markdown
Contributor

Relax is capable of expressing tensors whose element type is unknown. However, these must typically be replaced with a known dtype prior to compilation, as most operators require known data types prior to legalization. This can be done by using a relax::MatchCast node, such as accepting a parameter arg: R.Tensor([16,16]), then defining the dtype using R.match_cast(arg, R.Tensor([16,16],'float16')).

However, using a R.match_cast node requires knowing which data type should be used in the new R.Tensor, and raises an error for an incorrect data type. If an argument may be one of two distinct data types, R.match_cast cannot be used to check which data type is in use.

This commit adds Relax operators to read the runtime values of a DLTensor* argument. These can be be used to normalize arguments prior to a compute step. For example, pre-processing a model weight that may be provided in either float16 or bfloat16 format.

Relax is capable of expressing tensors whose element type is unknown.
However, these must typically be replaced with a known dtype prior to
compilation, as most operators require known data types prior to
legalization. This can be done by using a `relax::MatchCast` node,
such as accepting a parameter `arg: R.Tensor([16,16])`, then defining
the dtype using `R.match_cast(arg, R.Tensor([16,16],'float16'))`.
However, using a `R.match_cast` node requires knowing which data type
should be used in the new `R.Tensor`, and raises an error for an
incorrect data type. If an argument may be one of two distinct data
types, `R.match_cast` cannot be used to check which data type is in
use.
This commit adds Relax operators to read the runtime values of a
`DLTensor*` argument. These can be be used to normalize arguments
prior to a compute step. For example, pre-processing a model weight
that may be provided in either `float16` or `bfloat16` format.

@slyubomirskyslyubomirsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Comment threadpython/tvm/relax/expr.py Outdated

Used for early checks in `expr.dtype` and `expr.shape`
accessors. While invalid usage would cause errors to be
raised durin shape inference, an earlier check makes it easier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raiseddurinshapeinference, anearliercheckmakesiteasier
raisedduringshapeinference, anearliercheckmakesiteasier

typo

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and fixed

Comment on lines +287 to +288
Exposes accessors for `DLDataType` fields `type_code`, `lanes`,
and `bits` within a `DLTensor::dtype`. Accessing these fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good to have. Offset might also be useful to add, as it might help for memory reuse.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. At the moment, I stuck with the values that have a direct presence elsewhere in Relax, but I agree that it would be good to be able to extract any of the DLTensor* fields.

Comment threadsrc/relax/op/tensor/unpack.cc Outdated
*/

/*!
* \file unpack.cc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "unpack" is the best name. Perhaps "accessors" or "runtime_accessors" could be a little more descriptive? I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about relax.inspect(as a sub namespace for the ops)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like relax.inspect quite a bit, and will update the tensors to that namespace.

Comment on lines +225 to +227
// TODO(Lunderberg): Make a new operator attribute
// `.set_attr<Bool>("DataDependent")`, rather than relying on
// the name of the operator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, probably should be a separate PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The note is more so that it has a record somewhere, but it would be enough of a change that it should be part of a separate PR. As it was, I wanted to make as few changes to LegalizeOps as possible in this PR.

Comment on lines +192 to +204
// Improve this fallback case, as failure to legalize can
// produce unexpected errors during CodeGenVM. This could
// be done by having `R.Tensor(ndim=2)` be syntactic sugar
// for `R.Tensor(shape=[m, n])`, where `m` and `n` are new
// shape variables. This would allow legalization into
// dynamic TIR PrimFuncs.
//
// This fallback would only be applicable for cases where
// both the dtype and the dimensionality are known. While
// Relax can express a tensor with unknown dtype and
// dimensionality as `TensorStructInfo(DataType::Void(),
// kUnknownNDim)`, TIR cannot express unknown dtype or
// unknown dimensionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. This could be done by inserting a MatchCast that introduces the new vars. Perhaps this should be filed as an issue rather than made a long comment.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, though I haven't had time to flesh out the idea yet. This would be part of a general cleanup I'd propose for the StructInfo interactions:

  • Remove the Optional<Expr> shape and int ndim in TensorStructInfo. Instead, have Optional<ShapeStructInfo>.
  • Remove the ndim field from ShapeStructInfo. Instead, the ndim is unknown when Optional<Array<PrimExpr>> is NullOpt.
  • If the dimensionality of a ShapeStructInfo is known, every dimension must have an associated PrimExpr. The constructor that accepts ndim initializes fresh TIR variables to represent the unknown size.

)

@property
def dtype(self) -> "_DLTensorDTypeProxy":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the return type have to be in quotes? I assume it has to do with the property decorator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the order of definitions in the file. Function annotations are evaluated when the class is being defined. Since the _DLTensorDTypeProxy class is defined lower in the file, the type annotations are provided as a string, rather than as a class object.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Thank you! I really like polishing up the interface to be as clean as possible. (For my own sake if nothing else, as I am liable to forget a builtin-function name, but am much less likely to forget obj.dtype.)

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Prior to LegalizeOps, this is implicitly done by the FNormalize implementation for each operator. After LegalizeOps, not so much. While the FoldConstant pass can compile/run TIR functions if their arguments are known, there isn't a good way to indicate that a TIR function only requires the DLTensor struct, and not the data itself.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

All CI tests passing, and thank you for the review @slyubomirsky ! I'll follow up with another PR to add inspection of the remainder of the DLTensor* fields.

@Lunderberg
Lunderberg merged commit b218557 into apache:mainFeb 20, 2024
@Lunderberg
Lunderberg deleted the relax_unpack_ops branch February 20, 2024 20:59
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 14, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 15, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 18, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit that referenced this pull request Mar 26, 2024
…16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to #16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
…pache#16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Lunderberg@tqchen@slyubomirsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [Relax] Implement operators to read runtime DLTensor* information by Lunderberg · Pull Request #16563 · apache/tvm · GitHub
Skip to content

[Relax] Implement operators to read runtime DLTensor* information - #16563

Merged
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops
Feb 20, 2024
Merged

[Relax] Implement operators to read runtime DLTensor* information#16563
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops

Conversation

@Lunderberg

Copy link
Copy Markdown
Contributor

Relax is capable of expressing tensors whose element type is unknown. However, these must typically be replaced with a known dtype prior to compilation, as most operators require known data types prior to legalization. This can be done by using a relax::MatchCast node, such as accepting a parameter arg: R.Tensor([16,16]), then defining the dtype using R.match_cast(arg, R.Tensor([16,16],'float16')).

However, using a R.match_cast node requires knowing which data type should be used in the new R.Tensor, and raises an error for an incorrect data type. If an argument may be one of two distinct data types, R.match_cast cannot be used to check which data type is in use.

This commit adds Relax operators to read the runtime values of a DLTensor* argument. These can be be used to normalize arguments prior to a compute step. For example, pre-processing a model weight that may be provided in either float16 or bfloat16 format.

Relax is capable of expressing tensors whose element type is unknown.
However, these must typically be replaced with a known dtype prior to
compilation, as most operators require known data types prior to
legalization. This can be done by using a `relax::MatchCast` node,
such as accepting a parameter `arg: R.Tensor([16,16])`, then defining
the dtype using `R.match_cast(arg, R.Tensor([16,16],'float16'))`.
However, using a `R.match_cast` node requires knowing which data type
should be used in the new `R.Tensor`, and raises an error for an
incorrect data type. If an argument may be one of two distinct data
types, `R.match_cast` cannot be used to check which data type is in
use.
This commit adds Relax operators to read the runtime values of a
`DLTensor*` argument. These can be be used to normalize arguments
prior to a compute step. For example, pre-processing a model weight
that may be provided in either `float16` or `bfloat16` format.

@slyubomirskyslyubomirsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Comment threadpython/tvm/relax/expr.py Outdated

Used for early checks in `expr.dtype` and `expr.shape`
accessors. While invalid usage would cause errors to be
raised durin shape inference, an earlier check makes it easier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raiseddurinshapeinference, anearliercheckmakesiteasier
raisedduringshapeinference, anearliercheckmakesiteasier

typo

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and fixed

Comment on lines +287 to +288
Exposes accessors for `DLDataType` fields `type_code`, `lanes`,
and `bits` within a `DLTensor::dtype`. Accessing these fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good to have. Offset might also be useful to add, as it might help for memory reuse.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. At the moment, I stuck with the values that have a direct presence elsewhere in Relax, but I agree that it would be good to be able to extract any of the DLTensor* fields.

Comment threadsrc/relax/op/tensor/unpack.cc Outdated
*/

/*!
* \file unpack.cc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "unpack" is the best name. Perhaps "accessors" or "runtime_accessors" could be a little more descriptive? I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about relax.inspect(as a sub namespace for the ops)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like relax.inspect quite a bit, and will update the tensors to that namespace.

Comment on lines +225 to +227
// TODO(Lunderberg): Make a new operator attribute
// `.set_attr<Bool>("DataDependent")`, rather than relying on
// the name of the operator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, probably should be a separate PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The note is more so that it has a record somewhere, but it would be enough of a change that it should be part of a separate PR. As it was, I wanted to make as few changes to LegalizeOps as possible in this PR.

Comment on lines +192 to +204
// Improve this fallback case, as failure to legalize can
// produce unexpected errors during CodeGenVM. This could
// be done by having `R.Tensor(ndim=2)` be syntactic sugar
// for `R.Tensor(shape=[m, n])`, where `m` and `n` are new
// shape variables. This would allow legalization into
// dynamic TIR PrimFuncs.
//
// This fallback would only be applicable for cases where
// both the dtype and the dimensionality are known. While
// Relax can express a tensor with unknown dtype and
// dimensionality as `TensorStructInfo(DataType::Void(),
// kUnknownNDim)`, TIR cannot express unknown dtype or
// unknown dimensionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. This could be done by inserting a MatchCast that introduces the new vars. Perhaps this should be filed as an issue rather than made a long comment.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, though I haven't had time to flesh out the idea yet. This would be part of a general cleanup I'd propose for the StructInfo interactions:

  • Remove the Optional<Expr> shape and int ndim in TensorStructInfo. Instead, have Optional<ShapeStructInfo>.
  • Remove the ndim field from ShapeStructInfo. Instead, the ndim is unknown when Optional<Array<PrimExpr>> is NullOpt.
  • If the dimensionality of a ShapeStructInfo is known, every dimension must have an associated PrimExpr. The constructor that accepts ndim initializes fresh TIR variables to represent the unknown size.

)

@property
def dtype(self) -> "_DLTensorDTypeProxy":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the return type have to be in quotes? I assume it has to do with the property decorator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the order of definitions in the file. Function annotations are evaluated when the class is being defined. Since the _DLTensorDTypeProxy class is defined lower in the file, the type annotations are provided as a string, rather than as a class object.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Thank you! I really like polishing up the interface to be as clean as possible. (For my own sake if nothing else, as I am liable to forget a builtin-function name, but am much less likely to forget obj.dtype.)

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Prior to LegalizeOps, this is implicitly done by the FNormalize implementation for each operator. After LegalizeOps, not so much. While the FoldConstant pass can compile/run TIR functions if their arguments are known, there isn't a good way to indicate that a TIR function only requires the DLTensor struct, and not the data itself.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

All CI tests passing, and thank you for the review @slyubomirsky ! I'll follow up with another PR to add inspection of the remainder of the DLTensor* fields.

@Lunderberg
Lunderberg merged commit b218557 into apache:mainFeb 20, 2024
@Lunderberg
Lunderberg deleted the relax_unpack_ops branch February 20, 2024 20:59
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 14, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 15, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 18, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit that referenced this pull request Mar 26, 2024
…16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to #16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
…pache#16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Lunderberg@tqchen@slyubomirsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [Relax] Implement operators to read runtime DLTensor* information by Lunderberg · Pull Request #16563 · apache/tvm · GitHub
Skip to content

[Relax] Implement operators to read runtime DLTensor* information - #16563

Merged
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops
Feb 20, 2024
Merged

[Relax] Implement operators to read runtime DLTensor* information#16563
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops

Conversation

@Lunderberg

Copy link
Copy Markdown
Contributor

Relax is capable of expressing tensors whose element type is unknown. However, these must typically be replaced with a known dtype prior to compilation, as most operators require known data types prior to legalization. This can be done by using a relax::MatchCast node, such as accepting a parameter arg: R.Tensor([16,16]), then defining the dtype using R.match_cast(arg, R.Tensor([16,16],'float16')).

However, using a R.match_cast node requires knowing which data type should be used in the new R.Tensor, and raises an error for an incorrect data type. If an argument may be one of two distinct data types, R.match_cast cannot be used to check which data type is in use.

This commit adds Relax operators to read the runtime values of a DLTensor* argument. These can be be used to normalize arguments prior to a compute step. For example, pre-processing a model weight that may be provided in either float16 or bfloat16 format.

Relax is capable of expressing tensors whose element type is unknown.
However, these must typically be replaced with a known dtype prior to
compilation, as most operators require known data types prior to
legalization. This can be done by using a `relax::MatchCast` node,
such as accepting a parameter `arg: R.Tensor([16,16])`, then defining
the dtype using `R.match_cast(arg, R.Tensor([16,16],'float16'))`.
However, using a `R.match_cast` node requires knowing which data type
should be used in the new `R.Tensor`, and raises an error for an
incorrect data type. If an argument may be one of two distinct data
types, `R.match_cast` cannot be used to check which data type is in
use.
This commit adds Relax operators to read the runtime values of a
`DLTensor*` argument. These can be be used to normalize arguments
prior to a compute step. For example, pre-processing a model weight
that may be provided in either `float16` or `bfloat16` format.

@slyubomirskyslyubomirsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Comment threadpython/tvm/relax/expr.py Outdated

Used for early checks in `expr.dtype` and `expr.shape`
accessors. While invalid usage would cause errors to be
raised durin shape inference, an earlier check makes it easier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raiseddurinshapeinference, anearliercheckmakesiteasier
raisedduringshapeinference, anearliercheckmakesiteasier

typo

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and fixed

Comment on lines +287 to +288
Exposes accessors for `DLDataType` fields `type_code`, `lanes`,
and `bits` within a `DLTensor::dtype`. Accessing these fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good to have. Offset might also be useful to add, as it might help for memory reuse.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. At the moment, I stuck with the values that have a direct presence elsewhere in Relax, but I agree that it would be good to be able to extract any of the DLTensor* fields.

Comment threadsrc/relax/op/tensor/unpack.cc Outdated
*/

/*!
* \file unpack.cc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "unpack" is the best name. Perhaps "accessors" or "runtime_accessors" could be a little more descriptive? I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about relax.inspect(as a sub namespace for the ops)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like relax.inspect quite a bit, and will update the tensors to that namespace.

Comment on lines +225 to +227
// TODO(Lunderberg): Make a new operator attribute
// `.set_attr<Bool>("DataDependent")`, rather than relying on
// the name of the operator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, probably should be a separate PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The note is more so that it has a record somewhere, but it would be enough of a change that it should be part of a separate PR. As it was, I wanted to make as few changes to LegalizeOps as possible in this PR.

Comment on lines +192 to +204
// Improve this fallback case, as failure to legalize can
// produce unexpected errors during CodeGenVM. This could
// be done by having `R.Tensor(ndim=2)` be syntactic sugar
// for `R.Tensor(shape=[m, n])`, where `m` and `n` are new
// shape variables. This would allow legalization into
// dynamic TIR PrimFuncs.
//
// This fallback would only be applicable for cases where
// both the dtype and the dimensionality are known. While
// Relax can express a tensor with unknown dtype and
// dimensionality as `TensorStructInfo(DataType::Void(),
// kUnknownNDim)`, TIR cannot express unknown dtype or
// unknown dimensionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. This could be done by inserting a MatchCast that introduces the new vars. Perhaps this should be filed as an issue rather than made a long comment.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, though I haven't had time to flesh out the idea yet. This would be part of a general cleanup I'd propose for the StructInfo interactions:

  • Remove the Optional<Expr> shape and int ndim in TensorStructInfo. Instead, have Optional<ShapeStructInfo>.
  • Remove the ndim field from ShapeStructInfo. Instead, the ndim is unknown when Optional<Array<PrimExpr>> is NullOpt.
  • If the dimensionality of a ShapeStructInfo is known, every dimension must have an associated PrimExpr. The constructor that accepts ndim initializes fresh TIR variables to represent the unknown size.

)

@property
def dtype(self) -> "_DLTensorDTypeProxy":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the return type have to be in quotes? I assume it has to do with the property decorator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the order of definitions in the file. Function annotations are evaluated when the class is being defined. Since the _DLTensorDTypeProxy class is defined lower in the file, the type annotations are provided as a string, rather than as a class object.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Thank you! I really like polishing up the interface to be as clean as possible. (For my own sake if nothing else, as I am liable to forget a builtin-function name, but am much less likely to forget obj.dtype.)

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Prior to LegalizeOps, this is implicitly done by the FNormalize implementation for each operator. After LegalizeOps, not so much. While the FoldConstant pass can compile/run TIR functions if their arguments are known, there isn't a good way to indicate that a TIR function only requires the DLTensor struct, and not the data itself.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

All CI tests passing, and thank you for the review @slyubomirsky ! I'll follow up with another PR to add inspection of the remainder of the DLTensor* fields.

@Lunderberg
Lunderberg merged commit b218557 into apache:mainFeb 20, 2024
@Lunderberg
Lunderberg deleted the relax_unpack_ops branch February 20, 2024 20:59
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 14, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 15, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 18, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit that referenced this pull request Mar 26, 2024
…16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to #16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
…pache#16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Lunderberg@tqchen@slyubomirsky
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); [Relax] Implement operators to read runtime DLTensor* information by Lunderberg · Pull Request #16563 · apache/tvm · GitHub
Skip to content

[Relax] Implement operators to read runtime DLTensor* information - #16563

Merged
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops
Feb 20, 2024
Merged

[Relax] Implement operators to read runtime DLTensor* information#16563
Lunderberg merged 4 commits into
apache:mainfrom
Lunderberg:relax_unpack_ops

Conversation

@Lunderberg

Copy link
Copy Markdown
Contributor

Relax is capable of expressing tensors whose element type is unknown. However, these must typically be replaced with a known dtype prior to compilation, as most operators require known data types prior to legalization. This can be done by using a relax::MatchCast node, such as accepting a parameter arg: R.Tensor([16,16]), then defining the dtype using R.match_cast(arg, R.Tensor([16,16],'float16')).

However, using a R.match_cast node requires knowing which data type should be used in the new R.Tensor, and raises an error for an incorrect data type. If an argument may be one of two distinct data types, R.match_cast cannot be used to check which data type is in use.

This commit adds Relax operators to read the runtime values of a DLTensor* argument. These can be be used to normalize arguments prior to a compute step. For example, pre-processing a model weight that may be provided in either float16 or bfloat16 format.

Relax is capable of expressing tensors whose element type is unknown.
However, these must typically be replaced with a known dtype prior to
compilation, as most operators require known data types prior to
legalization. This can be done by using a `relax::MatchCast` node,
such as accepting a parameter `arg: R.Tensor([16,16])`, then defining
the dtype using `R.match_cast(arg, R.Tensor([16,16],'float16'))`.
However, using a `R.match_cast` node requires knowing which data type
should be used in the new `R.Tensor`, and raises an error for an
incorrect data type. If an argument may be one of two distinct data
types, `R.match_cast` cannot be used to check which data type is in
use.
This commit adds Relax operators to read the runtime values of a
`DLTensor*` argument. These can be be used to normalize arguments
prior to a compute step. For example, pre-processing a model weight
that may be provided in either `float16` or `bfloat16` format.

@slyubomirskyslyubomirsky left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Comment threadpython/tvm/relax/expr.py Outdated

Used for early checks in `expr.dtype` and `expr.shape`
accessors. While invalid usage would cause errors to be
raised durin shape inference, an earlier check makes it easier

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
raiseddurinshapeinference, anearliercheckmakesiteasier
raisedduringshapeinference, anearliercheckmakesiteasier

typo

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and fixed

Comment on lines +287 to +288
Exposes accessors for `DLDataType` fields `type_code`, `lanes`,
and `bits` within a `DLTensor::dtype`. Accessing these fields

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good to have. Offset might also be useful to add, as it might help for memory reuse.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. At the moment, I stuck with the values that have a direct presence elsewhere in Relax, but I agree that it would be good to be able to extract any of the DLTensor* fields.

Comment threadsrc/relax/op/tensor/unpack.cc Outdated
*/

/*!
* \file unpack.cc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if "unpack" is the best name. Perhaps "accessors" or "runtime_accessors" could be a little more descriptive? I'm not sure.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about relax.inspect(as a sub namespace for the ops)

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like relax.inspect quite a bit, and will update the tensors to that namespace.

Comment on lines +225 to +227
// TODO(Lunderberg): Make a new operator attribute
// `.set_attr<Bool>("DataDependent")`, rather than relying on
// the name of the operator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this, probably should be a separate PR.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. The note is more so that it has a record somewhere, but it would be enough of a change that it should be part of a separate PR. As it was, I wanted to make as few changes to LegalizeOps as possible in this PR.

Comment on lines +192 to +204
// Improve this fallback case, as failure to legalize can
// produce unexpected errors during CodeGenVM. This could
// be done by having `R.Tensor(ndim=2)` be syntactic sugar
// for `R.Tensor(shape=[m, n])`, where `m` and `n` are new
// shape variables. This would allow legalization into
// dynamic TIR PrimFuncs.
//
// This fallback would only be applicable for cases where
// both the dtype and the dimensionality are known. While
// Relax can express a tensor with unknown dtype and
// dimensionality as `TensorStructInfo(DataType::Void(),
// kUnknownNDim)`, TIR cannot express unknown dtype or
// unknown dimensionality.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting idea. This could be done by inserting a MatchCast that introduces the new vars. Perhaps this should be filed as an issue rather than made a long comment.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, though I haven't had time to flesh out the idea yet. This would be part of a general cleanup I'd propose for the StructInfo interactions:

  • Remove the Optional<Expr> shape and int ndim in TensorStructInfo. Instead, have Optional<ShapeStructInfo>.
  • Remove the ndim field from ShapeStructInfo. Instead, the ndim is unknown when Optional<Array<PrimExpr>> is NullOpt.
  • If the dimensionality of a ShapeStructInfo is known, every dimension must have an associated PrimExpr. The constructor that accepts ndim initializes fresh TIR variables to represent the unknown size.

)

@property
def dtype(self) -> "_DLTensorDTypeProxy":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does the return type have to be in quotes? I assume it has to do with the property decorator.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More the order of definitions in the file. Function annotations are evaluated when the class is being defined. Since the _DLTensorDTypeProxy class is defined lower in the file, the type annotations are provided as a string, rather than as a class object.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

The implementation seems solid, a very good change. I like the parameterized test cases too. The use of the _DLTensorShapeProxy resulted in an elegant UI in tvmscript.

Thank you! I really like polishing up the interface to be as clean as possible. (For my own sake if nothing else, as I am liable to forget a builtin-function name, but am much less likely to forget obj.dtype.)

Idle musing: I wonder if there's any way the PrimFuncs can be unrolled in cases where the parameters are known at compile time.

Prior to LegalizeOps, this is implicitly done by the FNormalize implementation for each operator. After LegalizeOps, not so much. While the FoldConstant pass can compile/run TIR functions if their arguments are known, there isn't a good way to indicate that a TIR function only requires the DLTensor struct, and not the data itself.

@Lunderberg

Copy link
Copy Markdown
ContributorAuthor

All CI tests passing, and thank you for the review @slyubomirsky ! I'll follow up with another PR to add inspection of the remainder of the DLTensor* fields.

@Lunderberg
Lunderberg merged commit b218557 into apache:mainFeb 20, 2024
@Lunderberg
Lunderberg deleted the relax_unpack_ops branch February 20, 2024 20:59
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 14, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 15, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit to Lunderberg/tvm that referenced this pull request Mar 18, 2024
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Lunderberg added a commit that referenced this pull request Mar 26, 2024
…16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to #16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
thaisacs pushed a commit to thaisacs/tvm that referenced this pull request Apr 3, 2024
…pache#16721)
* [TIR] LowerTVMBuiltin may use device_type from PrimFunc annotation
If an allocation occurs within a host function, it may not have a
device/host split.
* lint fix
* [Relax] Implement operators to inspec DLTensor::strides and offset
A follow-up PR to apache#16563. This PR
implements similar operators to inspect the runtime values of
`DLTensor::strides` and `DLTensor::byte_offset`. In addition, while the
element offset is not explicitly present in the `DLTensor` struct, a
Relax operator is implemented to infer it from the `byte_offset` and
`data_type` fields, for use when interacting with the TIR
`BufferNode::elem_offset` field.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Lunderberg@tqchen@slyubomirsky