-
Notifications
You must be signed in to change notification settings - Fork 6k
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
[AIR] Support array output from Torch model #24902
[AIR] Support array output from Torch model #24902
Conversation
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.
Overall LGTM. If we can't use TensorArray
here, then I think this should be good to merge
# these cannot be used as values in a Pandas Dataframe. | ||
# We have to convert the outermost dimension to a python list (but the values | ||
# in the list can still be Numpy arrays). | ||
return pd.DataFrame({"predictions": list(prediction)}, columns=["predictions"]) |
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.
Can we use TensorArray
here now that #24752 is merged?
return pd.DataFrame({"predictions": list(prediction)}, columns=["predictions"]) | |
return pd.DataFrame({"predictions": TensorArray(prediction)}, columns=["predictions"]) |
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 didn't want to have a ray.data dependency in Predictors. Once we do the data type conversion cleanup and probably move TensorArray
to a common utils file, I definitely agree though, we should use TensorArray here!
unsqueeze (bool): If set to True, the features tensors will be unsqueezed | ||
(reshaped to (N, 1)) before being concatenated into the final features | ||
tensor. Otherwise, they will be left as is, that is (N, ). | ||
Defaults to 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.
Nit: out of scope for this PR, but this explanation doesn't really make sense for multi-dimensional inputs
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.
We could change the description, yeah. We are now calling unsqueeze
which should work with an arbitrary number of dimensions and not just 2, like the view
call we were using before.
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.
Agreed the semantics here need to be changed. Though this is out of scope for this PR- this PR is just updating the docstring to match the same as the argument name, which is a mistake we had before.
def test_predict_array_output(): | ||
"""Tests if predictor works if model outputs an array instead of single value.""" | ||
|
||
predictor = TorchPredictor(model=model, preprocessor=preprocessor) |
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.
Nit: this is definitely out of scope for this PR, but it might be better to define model
and preprocessor
in the test because:
- Less confusion when reading the tests since all of the code is visible from within each test.
- Less chance of sharing state between tests, which creates unwanted dependencies between them.
Related advice from .NET's unit testing best practices.
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.
Updated!
def test_predict_array_output(): | ||
"""Tests if predictor works if model outputs an array instead of single value.""" | ||
|
||
predictor = TorchPredictor(model=model, preprocessor=preprocessor) |
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.
Just for my own understanding, why do we need to use a preprocessor 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.
I believe it is to check that its applied, though that could be covered by other tests and not this one specifically
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.
In this case I'd vote to leave it out of this test. We should ideally only test one thing
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.
Sounds good, I updated the tests! PTAL!
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.
Thanks, this looks good. +1 to Balaji's comment about using a TensorArray
once that's possible, though we probably don't need to block on that.
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.
Generally looks good once @bveeramani's comments are addressed
def test_predict_array_output(): | ||
"""Tests if predictor works if model outputs an array instead of single value.""" | ||
|
||
predictor = TorchPredictor(model=model, preprocessor=preprocessor) |
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.
In this case I'd vote to leave it out of this test. We should ideally only test one thing
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.
LGTM
The previous implementation of
TorchPredictor
failed when the model outputted an array for each sample (for example outputting logits). This is because Pandas Dataframes cannot hold numpy arrays of more than 1 element. We have to convert the outermost numpy array returned by the model to a list so that it be can stored in a Pandas Dataframe.The newly added test fails under the old implementation.
Why are these changes needed?
Related issue number
Checks
scripts/format.sh
to lint the changes in this PR.