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

Transform points op #2288

Merged
merged 7 commits into from
Sep 24, 2020
Merged

Transform points op #2288

merged 7 commits into from
Sep 24, 2020

Conversation

mzient
Copy link
Contributor

@mzient mzient commented Sep 21, 2020

Why we need this PR?

  • It adds new feature: operator that transforms coordinates
  • Allow empty shape (scalars) in Reshape op.

What happened in this PR?

Fill relevant points, put NA otherwise. Replace anything inside []

  • What solution was applied:
    • Added the operator
    • Modified Reshape to accept empty list as a shape.
  • Affected modules and functionalities:
    • The new operator(s)
    • Reshape
  • Key points relevant for the review:
    • N/A
  • Validation and testing:
    • Python test
  • Documentation (including examples):
    • Docstrings

JIRA TASK: DALI-1482, DALI-1605

@mzient mzient requested a review from a team September 21, 2020 09:18
@mzient mzient mentioned this pull request Sep 21, 2020
@mzient mzient force-pushed the TransformPointsOp branch 3 times, most recently from 01cfc50 to 3cf0a9c Compare September 21, 2020 15:05
DALI_SCHEMA(CoordTransform)
.DocStr(R"(Applies a linear transformation to points or vectors.


Copy link
Contributor

Choose a reason for hiding this comment

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

I think this bank is redundant.

) // NOLINT
) // NOLINT
), ( // NOLINT
DALI_FAIL(make_string("Unsupported input point dimensionality: ", input_pt_dim_));
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
DALI_FAIL(make_string("Unsupported input point dimensionality: ", input_pt_dim_));
DALI_FAIL(make_string("Unsupported output point dimensionality: ", input_pt_dim_));

FillDiag(make_span(&per_sample_mtx_[i * mat_size], mat_size), M.data[i][0]);
}
translation_.resize(output_pt_dim_, 0);
Repeat(per_sample_translation_, translation_, N);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can add a comment why the if (is_fused) is not relevant here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's doesn't change anything, but it should be here to avoid a redundant operation.

Copy link
Contributor

Choose a reason for hiding this comment

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

I know, but for consistency I would leave at least a comment that it is skipped on purpose here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What I meant is: the if should be here. I added it.

@mzient
Copy link
Contributor Author

mzient commented Sep 21, 2020

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1642398]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1642398]: BUILD PASSED

dali/operators/geometry/coord_transform.cc Show resolved Hide resolved
true)
.AddOptionalArg<vector<float>>("T", R"(The translation vector.

If left unspecified, no translation is applied.
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 necessarily true. You can still specify translation with MT

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will adjust.

translation_.resize(output_pt_dim_, 0);
}
} else {
DALI_ENFORCE(mtx_.size() % cols == 0, make_string("Cannot form a matrix ",
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
DALI_ENFORCE(mtx_.size() % cols == 0, make_string("Cannot form a matrix ",
DALI_ENFORCE(mtx_.size() % cols == 0, make_string("Cannot form a matrix with ",

}


vector<float> mtx_;
Copy link
Contributor

Choose a reason for hiding this comment

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

do you need those to be public?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the following scenarios it might be useful:

  1. If this class is used by composition instead of inheritance.
  2. ...or the derived class has pImpl.

@mzient
Copy link
Contributor Author

mzient commented Sep 22, 2020

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1645356]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1645356]: BUILD FAILED

@mzient
Copy link
Contributor Author

mzient commented Sep 22, 2020

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1646310]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1646310]: BUILD FAILED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1646310]: BUILD PASSED

Copy link
Contributor

@klecki klecki left a comment

Choose a reason for hiding this comment

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

Main points:

  • I think there is no check for degenerate argument of empty list, it will probably go through codepath for non-scalar argument provided.
  • repeating the obtaining and copying of regular argument in every iteration
  • ProcessMatrixArg is a bit long and hard to follow with the ifs, but isn't that bad.
  • some naming/typos.


namespace dali {

#define COORD_TRANSFORM_INPUT_TYPES (uint8_t, int16_t, uint16_t, int32_t, float)
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the reason for this particular subset of types?
This is only a side comment, but if adding more types usually becomes expensive, maybe we need to look into that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We need to limit the number of types, because the dimensionality is handled at compile-time and we already have 36 combinations there.
This set of types will allow us to process:

  • colors (uint8, uint16)
  • audio (int16, int32)
  • geometry (float)

If left unspecified, identity matrix is used.

The matrix ``M`` does not need to be square - if it's not, the output vectors will have a
different number of components.
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe add that it will be different than the input if we need to be really verbose. It sounds a bit like each of them can have a different number of components.


If left unspecified, no translation is applied unless MT argument is used.

The number of components of this vector must match the number of rows in matrix ``M``.
Copy link
Contributor

Choose a reason for hiding this comment

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

If we provide the matrix M as a flattened list of values, there isn't exactly a good notion of rows. Should we specify that the matrix should be provided as flattened row-major matrix?
(Ideally we would be able to accept anything array like with additional shape, but that would be a bit over the top in this PR).

translation_.resize(output_pt_dim_, 0);
}
} else {
DALI_ENFORCE(mtx_.size() % cols == 0, make_string("Cannot form a matrix with ",
Copy link
Contributor

Choose a reason for hiding this comment

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

What if mtx_.size() == 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Then we end up with empty output. It will raise a meaningful error later, when selecting the kernel.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Handled explicitly.

if (mtx_.size() == 1) {
SetOutputPtDim(input_pt_dim_);
mtx_.resize(output_pt_dim_ * input_pt_dim_);
FillDiag(mtx_, mtx_[0]);
Copy link
Contributor

Choose a reason for hiding this comment

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

FillDiag sounds like filling only the diagonal, maybe something like MakeDiagonalMat?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

if (is_fused)
translation_.clear();

if (HasMatrixRegularArg()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You will repeat the Regular arguments every iteration even though they do not change between them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's deliberate. I assume that at some point we'll allow the values of scalar arguments to change. Not that it would be very useful for this particular operator, but for random number generators, for example, it would have some merit.

} else if (HasMatrixInputArg()) {
const auto &M_inp = ws.ArgumentInput(name);
auto M = view<const float>(M_inp);
DALI_ENFORCE(is_uniform(M.shape), "Matrices for all samples int the batch must have "
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
DALI_ENFORCE(is_uniform(M.shape), "Matrices for all samples int the batch must have "
DALI_ENFORCE(is_uniform(M.shape), "Matrices for all samples in the batch must have "

Copy link
Contributor Author

Choose a reason for hiding this comment

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

:)

Copy link
Contributor

Choose a reason for hiding this comment

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

Happens to me all the time :P

Repeat(per_sample_mtx_, mtx_, N);
if (is_fused)
Repeat(per_sample_translation_, translation_, N);
} else if (HasMatrixInputArg()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like handling InputArg and regular arg could be two separate functions - this one is a tad long, I have to keep track of the if-nesting.

@@ -100,13 +100,13 @@ def _run_test(device, batch_size, out_dim, in_dim, in_dtype, out_dtype, M_kind,
Y = Y.clip(info.min, info.max)

ref.append(Y)
scale = max(scale, np.max(np.abs(Y)) - np.min(np.abs(Y)))
scale = max(scale, np.max(np.abs(Y)) - np.min(np.abs(Y))) if Y.size > 0 else 1
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this crashed for empty input

@mzient mzient force-pushed the TransformPointsOp branch 2 times, most recently from da6242f to 9e6c2af Compare September 23, 2020 16:30
@mzient
Copy link
Contributor Author

mzient commented Sep 23, 2020

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1648586]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1648586]: BUILD FAILED

Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
Added tests form MTTransformAttr.

Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
* Adjust documentation for argument M.
* Throw an error if M is empty.
* Fix typo.
* Check type in SetupImpl.
* Improve error message for unsupported type.
* Short-circuit if input is empty.
* Move layout setting to backend-agnostic part.
* Add tests for empty input.
* Test layouts.

Signed-off-by: Michał Zientkiewicz <mzient@gmail.com>
R"code(Transforms coordinates so that they are flipped (point reflected) with respect
to a center point.)code")
R"code(Transforms vectors or points by flipping (reflecting) their coordinates with
respect to a given center.)code")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We're not reflecting with respect to a point - we're reflecting with respect to multiple subspaces.

@mzient
Copy link
Contributor Author

mzient commented Sep 24, 2020

!build

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1650835]: BUILD STARTED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1650835]: BUILD FAILED

@dali-automaton
Copy link
Collaborator

CI MESSAGE: [1650835]: BUILD PASSED

@mzient mzient merged commit 104da7a into NVIDIA:master Sep 24, 2020
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.

5 participants