Skip to content

Conversation

@ysiraichi
Copy link
Collaborator

Follow up from: Quansight-Labs/numpy_pytorch_interop#3

This PR adds support for NumPy scalars for torch.asarray.

Before: treats the scalar as an object that implements the buffer protocol. Thus, interprets the data as the default data type (float32)

>>> torch.asarray(numpy.float64(0.5))
tensor([0.0000, 1.7500])

After: identifies the NumPy scalar, and does the "right" thing. i.e. creates a 0-dimensional tensor from the NumPy array that doesn't share its memory

>>> torch.asarray(numpy.float64(0.5))
tensor(0.5000, dtype=torch.float64)

@pytorch-bot
Copy link

pytorch-bot bot commented Dec 15, 2022

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/90914

Note: Links to docs will display an error until the docs builds have been completed.

✅ No Failures

As of commit 91a2bfc:
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@ysiraichi ysiraichi changed the title Numpy scalar asarray asarray: Add support for NumPy scalars Dec 16, 2022
Copy link
Collaborator

@lezcano lezcano left a comment

Choose a reason for hiding this comment

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

You mentioned that this method already works for numpy scalars if you add the dtype. Wouldn't it be possible (and simpler) to extract the type from the NumPy scalar and, if the dtype was not set, set it to that of the numpy scalar, and if the dtype was set, assert that both the dtypes are the same?

@mikaylagawarecki mikaylagawarecki added the triaged This issue has been looked at a team member, and triaged and prioritized into an appropriate module label Dec 16, 2022
@ysiraichi
Copy link
Collaborator Author

ysiraichi commented Dec 18, 2022

I would say that that is another solution to this problem. Here's a comparison between the 2:

Step Current Implementation Suggestion
1 NumPy scalar to NumPy array Check for NumPy scalar + Set the dtype
2 NumPy array to Tensor Buffer protocol to Tensor
3 Clone the tensor Slice* + Clone the tensor

* Slicing is needed so we return a 0-dimensional tensor.


Observing the steps above, I believe they are not significantly different (in added logic).
However, I would argue that:

  • Implementing NumPy scalar support near NumPy array support makes the code easier to understand
    • Common NumPy checks are coalesced into a single execution
  • It keeps the linearity of the prioritized type list (in the documentation)

Copy link
Collaborator

@rgommers rgommers left a comment

Choose a reason for hiding this comment

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

Thanks @ysiraichi. This LGTM, module a small comment on the docs. I don't have a clear preference between the two ways of implementing, they seem pretty similar and both work. Probably easiest to stay with the current logic.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This note is probably too prominent, and most users won't really care about the details here. The paragraph above suffices I think.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Instead of "but a NumPy scalar, a scalar or", how about "but a Python or NumPy scalar, or"?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That sounds better, indeed.

Copy link
Collaborator

@lezcano lezcano left a comment

Choose a reason for hiding this comment

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

Fair enough. There are many errors, but they don't seem related? Perhaps rebasing would make them go away?

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 a little confusing. The current documentation defines the follow priorities:

  • tensor, NumPy array, DLPack capsule
  • object implementing Python's buffer protocol
  • scalar or sequence of scalars

Doesn't this PR want to add NumPy scalar to the first category, taking precedence over objects that implement the buffer protocol? What happens if a sequence of NumPy scalars is given? Also, this paragraph says that the datatype of the returned tensor is inferred from the scalar values, but for a NumPy scalar isn't the returned tensor's dtype mapped from the NumPy scalar's 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.

Doesn't this PR want to add NumPy scalar to the first category, taking precedence over objects that implement the buffer protocol?

Yes, that's right.

What happens if a sequence of NumPy scalars is given?

They are treated as a Python sequence (i.e. datatype is inferred only if it's not explicitly specified).

Also, this paragraph says that the datatype of the returned tensor is inferred from the scalar values, but for a NumPy scalar isn't the returned tensor's dtype mapped from the NumPy scalar's dtype?

That's correct.
What if we added a new paragraph before this last one, like:

"When obj is a NumPy scalar, the returned tensor will be a 0-dimensional tensor that lives on the CPU device and doesn't share its memory (i.e. copy=True). Its datatype won't change unless otherwise specified."

Copy link
Collaborator

Choose a reason for hiding this comment

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

That addition LGTM, but let's see what Mike has to say.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Seems pretty reasonable. Small tweak suggestion:

"When obj is a NumPy scalar, the returned tensor will be a 0-dimensional tensor on the CPU and that doesn't share its memory (i.e. copy=True). By default datatype will be the PyTorch datatype corresponding to the NumPy's scalar's datatype."

?

@ysiraichi ysiraichi force-pushed the numpy-scalar-asarray branch from a6549cf to f68e282 Compare January 12, 2023 11:44
@lezcano
Copy link
Collaborator

lezcano commented Jan 12, 2023

PTAL @mruberry

@ysiraichi
Copy link
Collaborator Author

@mruberry This is a friendly reminder. Do you have some time to take a look at this PR?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Shouldn't this also test that tensor.dtype is float64?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes! Good catch

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.

Cool! See one testing suggestion

@ysiraichi
Copy link
Collaborator Author

@pytorchbot rebase

@pytorchmergebot
Copy link
Collaborator

@pytorchbot successfully started a rebase job. Check the current status here

@pytorchmergebot
Copy link
Collaborator

Successfully rebased numpy-scalar-asarray onto refs/remotes/origin/viable/strict, please pull locally before adding more changes (for example, via git checkout numpy-scalar-asarray && git pull --rebase)

@ysiraichi
Copy link
Collaborator Author

@pytorchbot merge

@pytorch-bot pytorch-bot bot added the ciflow/trunk Trigger trunk jobs on your pull request label Jan 23, 2023
@pytorchmergebot
Copy link
Collaborator

Merge started

Your change will be merged once all checks pass (ETA 0-4 Hours).

Learn more about merging in the wiki.

Questions? Feedback? Please reach out to the PyTorch DevX Team

Advanced Debugging
Check the merge workflow status
here

@pytorchmergebot
Copy link
Collaborator

Merge failed

Reason: 1 jobs have failed, first few of them are: trunk / macos-12-py3-x86-64-lite-interpreter / build

Details for Dev Infra team Raised by workflow job

@lezcano
Copy link
Collaborator

lezcano commented Jan 24, 2023

@pytorchbot merge

@pytorchmergebot
Copy link
Collaborator

Merge started

Your change will be merged once all checks pass (ETA 0-4 Hours).

Learn more about merging in the wiki.

Questions? Feedback? Please reach out to the PyTorch DevX Team

Advanced Debugging
Check the merge workflow status
here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ciflow/trunk Trigger trunk jobs on your pull request Merged 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.

7 participants