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

[numpy] torch.angle: promote integer inputs to float #49163

Conversation

kshitij12345
Copy link
Collaborator

@kshitij12345 kshitij12345 commented Dec 10, 2020

BC-Breaking Note:

This PR updates PyTorch's angle operator to be consistent with NumPy's. Previously angle would return zero for all floating point values (including NaN). Now angle returns pi for negative floating point values, zero for non-negative floating point values, and propagates NaNs.

PR Summary:

Reference: #42515

TODO:

  • Add BC-Breaking Note (Prev all real numbers returned 0 (even nan)) -> Fixed to match the correct behavior of NumPy.

@dr-ci
Copy link

dr-ci bot commented Dec 10, 2020

💊 CI failures summary and remediations

As of commit d95ff19 (more details on the Dr. CI page):


  • 1/1 failures possibly* introduced in this PR
    • 1/1 non-CircleCI failure(s)

This comment was automatically generated by Dr. CI (expand for details).Follow this link to opt-out of these comments for your Pull Requests.

Please report bugs/suggestions to the (internal) Dr. CI Users group.

This comment has been revised 35 times.

@codecov
Copy link

codecov bot commented Dec 11, 2020

Codecov Report

Merging #49163 (d95ff19) into master (7b4a766) will increase coverage by 5.48%.
The diff coverage is 93.75%.

@@            Coverage Diff             @@
##           master   #49163      +/-   ##
==========================================
+ Coverage   75.20%   80.69%   +5.48%     
==========================================
  Files        1886     1890       +4     
  Lines      204860   205005     +145     
==========================================
+ Hits       154073   165428   +11355     
+ Misses      50787    39577   -11210     

@kshitij12345 kshitij12345 mentioned this pull request Dec 11, 2020
8 tasks
@kshitij12345 kshitij12345 marked this pull request as ready for review December 15, 2020 12:55
@@ -167,7 +167,7 @@ static void abs_kernel(TensorIterator& iter) {
}

static void angle_kernel(TensorIterator& iter) {
AT_DISPATCH_ALL_TYPES_AND_COMPLEX_AND2(kBFloat16, kHalf, iter.dtype(), "angle_cpu", [&]() {
AT_DISPATCH_FLOATING_AND_COMPLEX_TYPES_AND2(kBFloat16, kHalf, iter.dtype(), "angle_cpu", [&]() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not dispatched on common_dtype but dtype?

}
Tensor angle(const Tensor& self) {
return unary_op_impl_with_complex_to_float(self, at::angle_out);
if (self.is_complex()) {
const auto float_type = c10::toValueType(self.scalar_type());
Copy link
Collaborator

Choose a reason for hiding this comment

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

Won't this run afoul of the safe casting logic in TensorIterator?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, sorry, it doesn't because it doesn't call tensor iterator, it calls angle_out.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is actually similar to what was already there.

if (self.is_complex()) {
const auto float_type = c10::toValueType(self.scalar_type());
Tensor result = at::empty({0}, self.options().dtype(float_type));
return out_impl(result, self);
}

@@ -35,7 +35,10 @@ inline double zabs <c10::complex<double>, double> (c10::complex<double> z) {

template <typename SCALAR_TYPE, typename VALUE_TYPE=SCALAR_TYPE>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a comment explaining this function

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think the name argument/arg is the more appropriate term from complex number perspective. What do you think?
But angle also makes sense as the user facing function is called angle.
About angle_impl, all the functions in zmath.h consistently have _impl suffix.

template <typename TYPE>
inline TYPE conj_impl (TYPE z) {
return z; //No-Op
}
template<>
inline c10::complex<float> conj_impl <c10::complex<float>> (c10::complex<float> z) {
return c10::complex<float>(z.real(), -z.imag());
}
template<>
inline c10::complex<double> conj_impl <c10::complex<double>> (c10::complex<double> z) {
return c10::complex<double>(z.real(), -z.imag());
}
template <typename TYPE>
inline TYPE ceil_impl (TYPE z) {
return std::ceil(z);
}
template <>
inline c10::complex<float> ceil_impl (c10::complex<float> z) {
return c10::complex<float>(std::ceil(z.real()), std::ceil(z.imag()));
}
template <>
inline c10::complex<double> ceil_impl (c10::complex<double> z) {
return c10::complex<double>(std::ceil(z.real()), std::ceil(z.imag()));
}
template<typename T>
inline c10::complex<T> sgn_impl (c10::complex<T> z) {
if (z == c10::complex<T>(0, 0)) {
return c10::complex<T>(0, 0);
} else {
return z / zabs(z);
}
}
template <typename TYPE>
inline TYPE floor_impl (TYPE z) {
return std::floor(z);
}
template <>
inline c10::complex<float> floor_impl (c10::complex<float> z) {
return c10::complex<float>(std::floor(z.real()), std::floor(z.imag()));
}
template <>

Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess we're stuck with "_impl", then. If the name is consistent then this PR doesn't need to bother updating it. But a comment explaining it would still be good.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@@ -11,7 +12,10 @@ namespace at { namespace native {
// We manually overload angle because std::arg does not work with types other than c10::complex.
template<typename scalar_t>
__host__ __device__ static inline scalar_t angle_wrapper(scalar_t v) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The name "angle_impl" in zmath.h seems odd to me, is there a better name? Maybe one that would fit a descriptive comment better?

@@ -20,7 +24,7 @@ __host__ __device__ static inline c10::complex<T> angle_wrapper(c10::complex<T>
}

void angle_kernel_cuda(TensorIterator& iter) {
AT_DISPATCH_ALL_TYPES_AND_COMPLEX(iter.dtype(), "angle_cuda", [&]() {
AT_DISPATCH_FLOATING_AND_COMPLEX_TYPES(iter.common_dtype(), "angle_cuda", [&]() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note the dispatch is on the common_dtype here

Copy link
Contributor

Choose a reason for hiding this comment

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

@kshitij12345 @mruberry why did we change it to common_dtype?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Reference:

#45733 (comment)

@@ -1253,8 +1270,6 @@ def method_tests():
('complex', (S, S, S), ((S, S, S),), ''),
('abs', (S, S, S), NO_ARGS, '', (True,)),
('abs', (), NO_ARGS, 'scalar', (True,)),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Reviewer's note:

There is another test for angle but it also tests abs:

def test_abs_angle_complex_to_float(self, device, dtype):

@mruberry
Copy link
Collaborator

Hey @kshitij12345! It's great to have a more consistent angle, an OpInfo for angle, and a int->float promoting angle. Overall this looks good. It needs a rebase, which should avoid the need for the skip, and I left a couple comments. Some of them are about improving the existing code's clarity.

@mrshenli mrshenli added module: numpy Related to numpy support, and also numpy compatibility of our operators triaged This issue has been looked at a team member, and triaged and prioritized into an appropriate module labels Dec 18, 2020
@kshitij12345
Copy link
Collaborator Author

@mruberry PTAL

@mruberry mruberry added the module: bc-breaking Related to a BC-breaking change label Dec 21, 2020
@@ -625,6 +625,10 @@ def merge_dicts(*dicts):
Keyword args:
{out}

.. note:: From version 1.8 onwards, the angle function returns `PI` for negative real numbers,
Copy link
Collaborator

Choose a reason for hiding this comment

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

"Starting in PyTorch 1.8, angle returns pi for negative real numbers, zero for non-negative real numbers, and propagates NaNs. Previously the function would return zero for all real numbers and not propagate floating-point NaNs."

@mruberry mruberry self-requested a review December 21, 2020 13:03
Copy link
Collaborator

@mruberry mruberry left a comment

Choose a reason for hiding this comment

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

Looks great! Just one easy docs update and then ping me to merge this.

@kshitij12345
Copy link
Collaborator Author

@mruberry PTAL :)

Failure looks irrelevant.

======================================================================
06:24:49 FAIL [0.096s]: test_embedding_bag_device_cuda_int32_float32 (__main__.TestNNDeviceTypeCUDA)
06:24:49 ----------------------------------------------------------------------
06:24:49 Traceback (most recent call last):
06:24:49   File "/var/lib/jenkins/.local/lib/python3.6/site-packages/torch/testing/_internal/common_utils.py", line 884, in wrapper
06:24:49     method(*args, **kwargs)
06:24:49   File "/var/lib/jenkins/.local/lib/python3.6/site-packages/torch/testing/_internal/common_utils.py", line 884, in wrapper
06:24:49     method(*args, **kwargs)
06:24:49   File "/var/lib/jenkins/.local/lib/python3.6/site-packages/torch/testing/_internal/common_device_type.py", line 273, in instantiated_test
06:24:49     result = test_fn(self, *args)
06:24:49   File "test_nn.py", line 12592, in test_embedding_bag_device
06:24:49     self._test_EmbeddingBag(device, 'mean', False, wdtype=dtypes[1], dtype=dtypes[0])
06:24:49   File "test_nn.py", line 12570, in _test_EmbeddingBag
06:24:49     self._test_EmbeddingBag_vs_Embedding(N, D, B, L, **kwargs)
06:24:49   File "test_nn.py", line 12422, in _test_EmbeddingBag_vs_Embedding
06:24:49     self.assertEqual(output, ref_output, atol=dtype2prec_DONTUSE[wdtype], rtol=0)
06:24:49   File "/var/lib/jenkins/.local/lib/python3.6/site-packages/torch/testing/_internal/common_utils.py", line 1175, in assertEqual
06:24:49     super().assertTrue(result, msg=self._get_assert_msg(msg, debug_msg=debug_msg))
06:24:49 AssertionError: False is not true : Tensors failed to compare as equal!With rtol=0 and atol=1e-05, found 49 element(s) (out of 225) whose difference(s) exceeded the margin of error (including 0 nan comparisons). The greatest difference was 0.315048448741436 (0.06700902432203293 vs. -0.24803942441940308), which occurred at index (0, 49).
06:24:49 

https://ci.pytorch.org/jenkins/job/pytorch-builds/job/pytorch-linux-bionic-rocm3.10-py3.6-test2/418/console

@mruberry
Copy link
Collaborator

Awesome! Would you just resolve the merge conflict?

@kshitij12345
Copy link
Collaborator Author

Done.

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

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

@mruberry has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@mruberry merged this pull request in 461aafe.

@kshitij12345 kshitij12345 deleted the develop/numpy/unary-float-op/angle branch December 23, 2020 05:14
auto angle_lambda = [](__m256 values) {
const auto zero_vec = _mm256_set1_ps(0.f);
const auto nan_vec = _mm256_set1_ps(NAN);
const auto not_nan_mask = _mm256_cmp_ps(values, values, _CMP_EQ_OQ);
Copy link
Contributor

Choose a reason for hiding this comment

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

sorry I am not very well versed with the AVX instructions ... what (nan related) information do we get by comparing values to itself?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since AVX itself does not have a special function for masking nans.
We use the property nan != nan to find the nan values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla signed Merged module: bc-breaking Related to a BC-breaking change module: numpy Related to numpy support, and also numpy compatibility of our operators open source triaged This issue has been looked at a team member, and triaged and prioritized into an appropriate module
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants