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
[numpy] torch.angle
: promote integer inputs to float
#49163
Conversation
💊 CI failures summary and remediationsAs of commit d95ff19 (more details on the Dr. CI page):
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 Report
@@ 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 |
@@ -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", [&]() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this run afoul of the safe casting logic in TensorIterator?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, sorry, it doesn't because it doesn't call tensor iterator, it calls angle_out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is actually similar to what was already there.
pytorch/aten/src/ATen/native/UnaryOps.cpp
Lines 105 to 109 in f5b68e7
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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a comment explaining this function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
pytorch/aten/src/ATen/native/cpu/zmath.h
Lines 114 to 163 in 76f7b73
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 <> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have added the following comment.
@@ -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) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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", [&]() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note the dispatch is on the common_dtype here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kshitij12345 @mruberry why did we change it to common_dtype
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reference:
@@ -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,)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewer's note:
There is another test for angle but it also tests abs:
pytorch/test/test_unary_ufuncs.py
Line 538 in 65876d3
def test_abs_angle_complex_to_float(self, device, dtype): |
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. |
@mruberry PTAL |
torch/_torch_docs.py
Outdated
@@ -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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"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."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Just one easy docs update and then ping me to merge this.
@mruberry PTAL :) Failure looks irrelevant.
|
Awesome! Would you just resolve the merge conflict? |
Done. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mruberry has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry I am not very well versed with the AVX instructions ... what (nan related) information do we get by comparing values to itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since AVX itself does not have a special function for masking nan
s.
We use the property nan != nan
to find the nan
values.
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:
0
(evennan
)) -> Fixed to match the correct behavior of NumPy.