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

to_device: Handle nested lists/tuples recursively #658

Merged
merged 8 commits into from
Jul 2, 2020

Conversation

ottonemo
Copy link
Member

The previous implementation of to_device would break when a
user decided to return a list of tensors in forward.

This patch applies to_device recursively and adds support
for lists in addition to tuples.

The previous implementation of `to_device` would break when a
user decided to return a list of tensors in `forward`.

This patch applies `to_device` recursively and adds support
for lists in addition to tuples.
@ottonemo ottonemo requested a review from BenjaminBossan June 23, 2020 21:22
Copy link
Collaborator

@BenjaminBossan BenjaminBossan left a comment

Choose a reason for hiding this comment

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

Thanks for the PR.

Just a heads up, there is also #657 working on to_device. Does it make sense to also adjust to_numpy with the same logic?

Also, it seems that when passing a list, to_device will return a tuple. Do you think it should be a list instead?

Co-authored-by: Benjamin Bossan <BenjaminBossan@users.noreply.github.com>
@ottonemo
Copy link
Member Author

Just a heads up, there is also #657 working on to_device. Does it make sense to also adjust to_numpy with the same logic?

I think it makes sense for predict_proba and transform. I will add it.

Also, it seems that when passing a list, to_device will return a tuple. Do you think it should be a list instead?

Fixed, thanks.

@ottonemo
Copy link
Member Author

@BenjaminBossan please review again.

@ottonemo
Copy link
Member Author

ottonemo commented Jun 24, 2020

@BenjaminBossan I think there's an issue with this when calling to_numpy([1,2,3]). Before this returned a numpy array, now it doesn't anymore. Please don't merge this yet.

Edit: I checked and this is not a regression. So everything is fine and this can be merged.

@BenjaminBossan
Copy link
Collaborator

I think there's an issue with this when calling to_numpy([1,2,3]). Before this returned a numpy array, now it doesn't anymore. Please don't merge this yet.

Is it correct that this raises a TypeError (old and new implementation)? I wonder if that's the desired behavior and if it is, if we should clarify that with a corresponding test.

@ottonemo
Copy link
Member Author

I think there's an issue with this when calling to_numpy([1,2,3]). Before this returned a numpy array, now it doesn't anymore. Please don't merge this yet.

Is it correct that this raises a TypeError (old and new implementation)? I wonder if that's the desired behavior and if it is, if we should clarify that with a corresponding test.

This is a question of scope. to_numpy was originally introduced to convert from PyTorch to numpy and included device handling / gradient detaching. Now we are transitioning away from that definition by handling other data types as well but its main purpose is still to convert from PyTorch to numpy (even when we are unpacking other data types). If you agree with this definition we should

  1. make this explicit in the docs
  2. make this explicit in the tests (check for TypeError when supplying non-pytorch data, even if nested)

@BenjaminBossan
Copy link
Collaborator

That sounds very reasonable, I think to_numpy shouldn't grow in scope beyond what it delivers at the moment, it was really only meant to be a convenience function.

@ottonemo ottonemo requested a review from BenjaminBossan July 1, 2020 17:04
{'a': 1},
])
def test_invalid_inputs(self, to_numpy, x_invalid):
" Inputs that are invalid for the scope of to_numpy. "
Copy link
Collaborator

Choose a reason for hiding this comment

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

I've never seen this style, neither docstring nor comment. I think a comment would be sufficient here?

Copy link
Member Author

Choose a reason for hiding this comment

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

It is still a doc-string but according to PEP257 this style is disregarded. I converted it to a comment.

Example:

>>> def foo():
...     "bla"
...     return 1
... 
>>> foo.__doc__
'bla'

Copy link
Collaborator

Choose a reason for hiding this comment

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

It is still a doc-string but according to PEP257 this style is disregarded

Interesting, I didn't know, though in hindsight it makes sense.

Copy link
Collaborator

@BenjaminBossan BenjaminBossan left a comment

Choose a reason for hiding this comment

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

LGTM

@BenjaminBossan BenjaminBossan merged commit 6e9cc18 into master Jul 2, 2020
@BenjaminBossan BenjaminBossan deleted the issue/nested-lists-to-device branch July 30, 2020 22:25
BenjaminBossan added a commit that referenced this pull request Aug 30, 2020
This release of skorch contains a few minor improvements and some nice additions. As always, we fixed a few bugs and improved the documentation. Our [learning rate scheduler](https://skorch.readthedocs.io/en/latest/callbacks.html#skorch.callbacks.LRScheduler) now optionally logs learning rate changes to the history; moreover, it now allows the user to choose whether an update step should be made after each batch or each epoch.

If you always longed for a metric that would just use whatever is defined by your criterion, look no further than [`loss_scoring`](https://skorch.readthedocs.io/en/latest/scoring.html#skorch.scoring.loss_scoring). Also, skorch now allows you to easily change the kind of nonlinearity to apply to the module's output when `predict` and `predict_proba` are called, by passing the `predict_nonlinearity` argument.

Besides these changes, we improved the customization potential of skorch. First of all, the `criterion` is now set to `train` or `valid`, depending on the phase -- this is useful if the criterion should act differently during training and validation. Next we made it easier to add custom modules, optimizers, and criteria to your neural net; this should facilitate implementing architectures like GANs. Consult the [docs](https://skorch.readthedocs.io/en/latest/user/neuralnet.html#subclassing-neuralnet) for more on this. Conveniently, [`net.save_params`](https://skorch.readthedocs.io/en/latest/net.html#skorch.net.NeuralNet.save_params) can now persist arbitrary attributes, including those custom modules.
As always, these improvements wouldn't have been possible without the community. Please keep asking questions, raising issues, and proposing new features. We are especially grateful to those community members, old and new, who contributed via PRs:

```
Aaron Berk
guybuk
kqf
Michał Słapek
Scott Sievert
Yann Dubois
Zhao Meng
```

Here is the full list of all changes:

### Added

- Added the `event_name` argument for `LRScheduler` for optional recording of LR changes inside `net.history`. NOTE: Supported only in Pytorch>=1.4
- Make it easier to add custom modules or optimizers to a neural net class by automatically registering them where necessary and by making them available to set_params
- Added the `step_every` argument for `LRScheduler` to set whether the scheduler step should be taken on every epoch or on every batch.
- Added the `scoring` module with `loss_scoring` function, which computes the net's loss (using `get_loss`) on provided input data.
- Added a parameter `predict_nonlinearity` to `NeuralNet` which allows users to control the nonlinearity to be applied to the module output when calling `predict` and `predict_proba` (#637, #661)
- Added the possibility to save the criterion with `save_params` and with checkpoint callbacks
- Added the possibility to save custom modules with `save_params` and with checkpoint callbacks

### Changed

- Removed support for schedulers with a `batch_step()` method in `LRScheduler`.
- Raise `FutureWarning` in `CVSplit` when `random_state` is not used. Will raise an exception in a future (#620)
- The behavior of method `net.get_params` changed to make it more consistent with sklearn: it will no longer return "learned" attributes like `module_`; therefore, functions like `sklearn.base.clone`, when called with a fitted net, will no longer return a fitted net but instead an uninitialized net; if you want a copy of a fitted net, use `copy.deepcopy` instead;`net.get_params` is used under the hood by many sklearn functions and classes, such as `GridSearchCV`, whose behavior may thus be affected by the change. (#521, #527)
- Raise `FutureWarning` when using `CyclicLR` scheduler, because the default behavior has changed from taking a step every batch to taking a step every epoch. (#626)
- Set train/validation on criterion if it's a PyTorch module (#621)
- Don't pass `y=None` to `NeuralNet.train_split` to enable the direct use of split functions without positional `y` in their signatures. This is useful when working with unsupervised data (#605).
- `to_numpy` is now able to unpack dicts and lists/tuples (#657, #658)
- When using `CrossEntropyLoss`, softmax is now automatically applied to the output when calling `predict` or `predict_proba`

### Fixed

- Fixed a bug where `CyclicLR` scheduler would update during both training and validation rather than just during training.
- Fixed a bug introduced by moving the `optimizer.zero_grad()` call outside of the train step function, making it incompatible with LBFGS and other optimizers that call the train step several times per batch (#636)
- Fixed pickling of the `ProgressBar` callback (#656)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants