-
Notifications
You must be signed in to change notification settings - Fork 52
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
Data dependent/unknown shapes #97
Comments
That makes sense. A custom tuple-like object, with |
We actually already allow for either a tuple or a custom shape object (https://data-apis.github.io/array-api/latest/API_specification/array_object.html#shape), so it's |
Remind me why we allow the custom object? Is it just because that's what
TensorFlow currently does or is there a more specific use case?
…On Thu, Dec 3, 2020 at 1:30 PM Ralf Gommers ***@***.***> wrote:
We actually already allow for either a tuple or a custom shape object (
https://data-apis.github.io/array-api/latest/API_specification/array_object.html#shape),
so it's None vs. nan that needs deciding.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#97 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAJJFVRG5AFMXEEYJPLZ5R3SS77N3ANCNFSM4UMQRVAQ>
.
|
IIRC because using Python objects (ints, tuples, etc.) rather than custom ones can force extra synchronizations. PyTorch also uses a custom object:
|
I guess this is for cases where some parts of Interestingly, I think TensorFlow has this for different reasons, possibly just for preserving backwards compatibility at this point. It has two ways of accessing shape information: |
It may be due to legacy reasons in PyTorch as well. From pytorch/pytorch#20823 (comment): I remember a discussion about this when we reviewed the array object API, and someone (probably @alextp or @apaszke) suggested adding the custom object. |
I think the custom object is only useful when you want to deal with staged computation like @shoyer mentions above. TF2 stopped using the wrapped Dimension type and just has its TensorShape be a tuple of either integers or None to indicate shapes which we do not know at tracing time. So I think saying shapes are tuples here is probably a good idea. |
TensorFlow (and TF NumPy) will be returning a TensorShape object and Perhaps we should reconsider allowing custom objects. |
I think this is a bug in tf.numpy, then.
…On Wed, Dec 9, 2020 at 11:08 PM token ***@***.***> wrote:
TensorFlow (and TF NumPy) will be returning a TensorShape object and tensor.shape
is None will not work when checking for unknown rank.
Perhaps we should reconsider allowing custom objects.
Alternatively users could check for ndarray.ndim is None leaving
ndarray.shape undefined for unknown rank cases.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#97 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAABHRP6KUAHRFPNCVZRBODSUBXVHANCNFSM4UMQRVAQ>
.
--
- Alex
|
After writing this: we did include Leaving any property (like
Maybe we should say "shape is tuple" and add a note that if for backwards compat reasons an implementation is using a custom object, then it should make sure that it is a subtype of tuple so that it works when users annotate code using |
This might be an argument for requiring an
Agreed! |
If we insist that rank is always statically known, then shape being None is moot and we can define shape to be a tuple (or tuple-like) object. Regarding custom objects, if the object represents a union of tuple and None, then it doesn't sound correct to subclass this union from tuple: a subclass of tuple should not satisfy TensorFlow's TensorShape object implements most of the tuple methods but is not subclassed from it since it represents an optional tuple. Instead it raises exception in certain methods when rank is unknown. |
Agreed. I said subtype rather than subclass (as in structural subtyping). To clarify, I'd like it to be possible for users to use type annotation This implies that the custom object must behave tuple-like; you can index it, |
I like that idea, I'll open a PR so we can discuss there. |
As suggested by @shoyer in #97 (comment) This makes it possible to predict resulting rank of output array, which is otherwise undetermined (see discussion in gh-97). Using squeeze without specifying the axis in library code often results in unintuitive behaviour. For the common use case of extracting a scalar from a size-1 2-D array, this gets a little more verbose (e.g. `np.squeeze(np.array([[1]]), axis=(0, 1))`), but that's probably a price worth paying for the extra clarity. Also changes specified behaviour for a given axis not having size 1 to raising a `ValueError`, which is what NumPy does. This wasn't considered before, and the current description seems simply incorrect. Finally, this makes `squeeze` the exact inverse of `expand_dims`, which is probably a good thing.
As suggested by @shoyer in data-apis#97 (comment) This makes it possible to predict resulting rank of output array, which is otherwise undetermined (see discussion in data-apisgh-97). Using squeeze without specifying the axis in library code often results in unintuitive behaviour. For the common use case of extracting a scalar from a size-1 2-D array, this gets a little more verbose (e.g. `np.squeeze(np.array([[1]]), axis=(0, 1))`), but that's probably a price worth paying for the extra clarity. Also changes specified behaviour for a given axis not having size 1 to raising a `ValueError`, which is what NumPy does. This wasn't considered before, and the current description seems simply incorrect. Finally, this makes `squeeze` the exact inverse of `expand_dims`, which is probably a good thing.
As suggested by @shoyer in data-apis#97 (comment) This makes it possible to predict resulting rank of output array, which is otherwise undetermined (see discussion in data-apisgh-97). Using squeeze without specifying the axis in library code often results in unintuitive behaviour. For the common use case of extracting a scalar from a size-1 2-D array, this gets a little more verbose (e.g. `np.squeeze(np.array([[1]]), axis=(0, 1))`), but that's probably a price worth paying for the extra clarity. Also changes specified behaviour for a given axis not having size 1 to raising a `ValueError`, which is what NumPy does. This wasn't considered before, and the current description seems simply incorrect. Finally, this makes `squeeze` the exact inverse of `expand_dims`, which is probably a good thing.
The main reason Dask chose |
Conversely, the danger of NaN is that it doesn't quite have the right semantics for array sizes, e.g., it's always False in comparisons rather than producing another "unknown" value. The ideal solution for minimal boilerplate might be a new object to denote a missing value, like |
As suggested by @shoyer in #97 (comment) This makes it possible to predict resulting rank of output array, which is otherwise undetermined (see discussion in gh-97). Using squeeze without specifying the axis in library code often results in unintuitive behaviour. For the common use case of extracting a scalar from a size-1 2-D array, this gets a little more verbose (e.g. `np.squeeze(np.array([[1]]), axis=(0, 1))`), but that's probably a price worth paying for the extra clarity. Also changes specified behaviour for a given axis not having size 1 to raising a `ValueError`, which is what NumPy does. This wasn't considered before, and the current description seems simply incorrect. Finally, this makes `squeeze` the exact inverse of `expand_dims`, which is probably a good thing.
To summarize the above discussion and the discussions during the consortium meetings (e.g., 7 October 2021), the path forward seems to be as follows:
We can consider adding a functional The above would not satisfy @jakirkham's desire for behavior which poisons subsequent operations; however, as discussed here and elsewhere, A custom object as suggested by @shoyer would be doable; however, this is an abstraction which does not currently exist in or is used by array libraries (although, it does exist in dataframe libraries, such as pandas) and would be specific to each implementing array library. The advantage of Accordingly, I think the lowest common denominator is requiring |
Based on today's call (4 November 2021), we decided to require For the possibility that @rgommers mentioned of explicitly squeezing a data dependent shape, array libraries could choose to error in this instance or explicitly evaluate. |
Some libraries, particularly those with a graph-based computational model (e.g., Dask and TensorFlow), have support for "unknown" or "data dependent" shapes, e.g., due to boolean indexing such as
x[y > 0]
(#84). Other libraries (e.g., JAX and Dask in some cases) do not support some operations because they would produce such data dependent shapes.We should consider a standard way to represent these shapes in
shape
attributes, ideally some extension of the "tuple of integer" format used for fully known shapes. For example, TensorFlow and Dask currently use different representations:TensorShape
object (which acts very similarly totuple
), where some values may beNone
nan
integer of integersThe text was updated successfully, but these errors were encountered: