Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Expand dims operator #2800

Merged
merged 28 commits into from
Mar 18, 2021
Merged

Add Expand dims operator #2800

merged 28 commits into from
Mar 18, 2021

Conversation

majra20
Copy link
Contributor

@majra20 majra20 commented Mar 16, 2021

Why we need this PR?

  • It adds new feature with new operator

What happened in this PR?

  • What solution was applied:
    • Added ExpandDims operator
  • Affected modules and functionalities:
    • ExpandDims operator which allows to squeeze dimensions of size one
  • Key points relevant for the review:
    • ExpandDims operator code, does it do everything we wanted
  • Validation and testing:
    • Python tests: test_operator_expand_dims.py
  • Documentation (including examples):
    NA

JIRA TASK: DALI-1851

std::vector<int>(), true)
.AddOptionalArg("new_axis_names", R"code(Names of new dimensions in data layout.

Size of ``new_axis_names`` should be equal to ``axe``s size.
Copy link
Contributor

Choose a reason for hiding this comment

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

The length of new_axis_names must match the length of axes.

Comment on lines 97 to 98
}
out_layout += in_layout.empty() ? '?' : in_layout[d];
Copy link
Contributor

Choose a reason for hiding this comment

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

If the input doesn't have a well defined layout, the output layout should also be empty.

The logic should be something like:

if (1) input has layout
    if (2) new_axis_names_ match the length of axes:
        output layout is a product of inserting new_axis_names at `axes`
    else
        either (3) reset layout to empty or (4) insert `?`
else
    (5) output layout is empty

(1) - We should assume that 0D input with empty layout has proper layout
(2) - This differs from new_axis_names.empty() in case when axes are also empty
(3) - This is consistent with (5) for 0D and >0D
(4) - This is inconsistent

Elaborating on inconsistency between (4) and (5):
A 0D has both specified and empty layout (layout is not a nullable property).
Now, if we insert ?, a 0D tensor will never be expanded to one with empty layout, even though it's very likely that the user wants it - instead, the tensor will get a (possibly invalid) layout with multiple ? inserted.

Examples of the proposed logic:

ndim = 2
layout = HW
axes = [2]
axis_names = C
output layout HWC

ndim = 2
layout
axes = [2]
axis_names = 'C'
output: error - specifying axis names requires an input with a proper layuout

ndim = 2
layout = HW
axes = []
new_axis_names = ""
output layout = HW

ndim = 0
layout = ""
axes = [0, 1]
new_axis_names = "HW"
output layout = HW

ndim = 0
layout = ""
axes = [0, 1]
new_axis_names = ""
output layout = ""

ndim = 2
layout = "HW"
axes = [0]
new_axis_names = ""
output layout = ""

Comment on lines 29 to 30
.DocStr(R"code(Insert new dimension[s] of extent 1 and inserts new entries in "
"the layout (new_axis_names) at these indices in the layout.)code")
Copy link
Contributor

Choose a reason for hiding this comment

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

We probably want a shorter first description for the table of operators.
I'd say

Suggested change
.DocStr(R"code(Insert new dimension[s] of extent 1 and inserts new entries in "
"the layout (new_axis_names) at these indices in the layout.)code")
.DocStr(R"code(Insert new dimension(s) with extent 1 to the data shape.
The new dimensions are inserted at the positions specified by ``axes``.
If ``new_axis_names`` is provided, the new dimension names will be inserted in the data layout, at the positions specified by ``axes``. If ``new_axis_names`` is not provided, the output data layout will be empty.")code")

.PassThrough({{0, 0}})
.AllowSequences()
.SupportVolumetric()
.AddOptionalArg<int>("axes", R"code(Indices where to put new dimensions of size 1.)code",
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.AddOptionalArg<int>("axes", R"code(Indices where to put new dimensions of size 1.)code",
.AddOptionalArg<int>("axes", R"code(Indices representing the positions in the data shape where a new dimension with extent 1 will be inserted.
The indices should be in the range ``[0, ndim]``, where ``ndim`` is the number of dimensions in the input. Providing the index ``ndim`` results in a new dimension appended at the end of the shape.)code",

.SupportVolumetric()
.AddOptionalArg<int>("axes", R"code(Indices where to put new dimensions of size 1.)code",
std::vector<int>(), true)
.AddOptionalArg("new_axis_names", R"code(Names of new dimensions in data layout.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.AddOptionalArg("new_axis_names", R"code(Names of new dimensions in data layout.
.AddOptionalArg("new_axis_names", R"code(Names of the new dimensions in the data layout.

new_axis_names_ = spec.GetArgument<TensorLayout>("new_axis_names");
if (!new_axis_names_.empty()) {
DALI_ENFORCE(new_axis_names_.size() == axes_.size(), make_string("Specified ", axes_.size(),
" new dimensions, but layout specify ", new_axis_names_.size(), " new names"));
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
" new dimensions, but layout specify ", new_axis_names_.size(), " new names"));
" new dimensions, but layout contains only ", new_axis_names_.size(), " new dimension names"));

.PassThrough({{0, 0}})
.AllowSequences()
.SupportVolumetric()
.AddOptionalArg<int>("axes", R"code(Indices where to put new dimensions of size 1.)code",
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.AddOptionalArg<int>("axes", R"code(Indices where to put new dimensions of size 1.)code",
.AddOptionalArg<int>("axes", R"code(Indices at which the new dimensions are inserted.
.)code",

Rafal Maj added 24 commits March 17, 2021 12:58
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
Signed-off-by: Rafal Maj <rmaj@nvidia.com>
.AddOptionalArg("new_axis_names", R"code(Names of the new dimensions in the data layout.

The length of ``new_axis_names`` must match the length of ``axes``.
If argument won't be provided new dimensions will have layout '?')code", TensorLayout(""));
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
If argument won't be provided new dimensions will have layout '?')code", TensorLayout(""));
If argument isn't be provided new dimensions will have layout '?')code", TensorLayout(""));

.AddOptionalArg("new_axis_names", R"code(Names of the new dimensions in the data layout.

The length of ``new_axis_names`` must match the length of ``axes``.
If argument won't be provided layout will be cleared.)code", TensorLayout(""));
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
If argument won't be provided layout will be cleared.)code", TensorLayout(""));
If argument is not provided, output layout will be cleared.)code", TensorLayout(""));

or

Suggested change
If argument won't be provided layout will be cleared.)code", TensorLayout(""));
If argument is not provided, the layout will be cleared.)code", TensorLayout(""));

ExpandDims<Backend>::ExpandDims(const OpSpec &spec)
: Reshape<Backend>(spec, typename Reshape<Backend>::BypassInit()) {
axes_ = spec.GetRepeatedArgument<int>("axes");
DALI_ENFORCE(spec.HasArgument("axes"), make_string("``axes`` argument should be provided."));
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not necessary. Just make the argument mandatory in the schema.

Comment on lines 41 to 42
.AddOptionalArg<int>("axes", R"code(Indices at which the new dimensions are inserted.)code",
std::vector<int>(), true)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
.AddOptionalArg<int>("axes", R"code(Indices at which the new dimensions are inserted.)code",
std::vector<int>(), true)
.AddArg("axes", R"code(Indices at which the new dimensions are inserted.)code",
DALI_INT_VEC, true)

}
std::sort(axes_.begin(), axes_.end());
DALI_ENFORCE(std::adjacent_find(axes_.begin(), axes_.end()) == axes_.end(),
make_string("Specified at least twice same index to add new dimension."));
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
make_string("Specified at least twice same index to add new dimension."));
make_string("Duplicate axis index found."));

Signed-off-by: Rafal Maj <rmaj@nvidia.com>
auto in_layout = in.GetLayout();
if (in_layout.empty() && ndim) {
DALI_ENFORCE(!use_new_axis_names_arg_,
make_string("Specifying ``new_axis_names`` requires an input with a proper layuout."));
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
make_string("Specifying ``new_axis_names`` requires an input with a proper layuout."));
make_string("Specifying ``new_axis_names`` requires an input with a proper layout."));

Signed-off-by: Rafal Maj <rmaj@nvidia.com>
@majra20
Copy link
Contributor Author

majra20 commented Mar 18, 2021

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2179748]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [2179748]: BUILD PASSED

@majra20 majra20 merged commit e442122 into NVIDIA:master Mar 18, 2021
@majra20 majra20 deleted the expand_dims branch March 18, 2021 09:55
Sign up for free to 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.

4 participants