-
Notifications
You must be signed in to change notification settings - Fork 325
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
[Feature] adding tensor classes annotation for loss functions #1905
base: main
Are you sure you want to change the base?
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/rl/1905
Note: Links to docs will display an error until the docs builds have been completed. ❌ 14 New FailuresAs of commit 9b5f4e6 with merge base 87f3437 (): NEW FAILURES - The following jobs have failed:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
3c3bc29
to
0e993e4
Compare
0e993e4
to
e4761a3
Compare
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 promising!
I'd suggest adding the args to the docstrings and make a single test for each loss that we can get the tensorclass and the we can access the losses inf return_tensorclass
is True
@@ -234,6 +250,7 @@ def __init__( | |||
functional: bool = True, | |||
actor: ProbabilisticTensorDictSequential = None, | |||
critic: ProbabilisticTensorDictSequential = None, | |||
return_tensorclass: bool = False, |
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.
Should be added to the docstrings
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.
working on it.
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.
@vmoens added doctests for tensorclass changes. but I see some doctest issues and blockers. can you please help me resolve.
- there are some existing doctest failures, we might need a separate task to address.
- what would be the aggregate_loss for each loss within tensorclass?
- there are some existing errors like
```Cannot interpret 'torch.int64' as a data type```
```'key "action_value" not found in TensorDict with keys [\'done\', \'logits\', \'observation\', \'reward\', \'state_value\', \'terminated\']' ```
```NameError: name 'actor' is not defined```
- etc
7d6e08f
to
8e16b63
Compare
# Conflicts: # torchrl/objectives/ppo.py
Subscribers: Tasks: Tags:
@vmoens can you review once, build errors on resource not related to the PR. |
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!
New classes should be manually added to the doc
See docs/source/reference/objectives.rst
The feature seems untested to me, am I right?
test/test_cost.py
Outdated
|
||
loss_function="l2", | ||
|
||
delay_value=delay_value, | ||
|
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.
not sure why we need these
torchrl/objectives/a2c.py
Outdated
@@ -33,6 +35,34 @@ | |||
) | |||
|
|||
|
|||
class LossContainerBase: | |||
"""ContainerBase class loss tensorclass's.""" |
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.
That isn't very explicit. We should say what this class is about.
Also I think it should live in the common.py
file.
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'm also wondering if we should not just make the base a tensorclass and inherit from it without creating new tensorclasses?
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.
If I try to make the base a tensorclass getting below error.
**********************************************************************
File "/home/sandish/rl/torchrl/objectives/a2c.py", line 144, in a2c.A2CLoss
Failed example:
loss(data)
Exception raised:
Traceback (most recent call last):
File "/home/sandish/.conda/envs/torch_rl/lib/python3.9/doctest.py", line 1334, in __run
exec(compile(example.source, filename, "single",
File "<doctest a2c.A2CLoss[21]>", line 1, in <module>
loss(data)
File "/home/sandish/.conda/envs/torch_rl/lib/python3.9/site-packages/torch/nn/modules/module.py", line 1511, in _wrapped_call_impl
return self._call_impl(*args, **kwargs)
File "/home/sandish/.conda/envs/torch_rl/lib/python3.9/site-packages/torch/nn/modules/module.py", line 1561, in _call_impl
result = forward_call(*args, **kwargs)
File "/home/sandish/.conda/envs/torch_rl/lib/python3.9/site-packages/tensordict/_contextlib.py", line 126, in decorate_context
return func(*args, **kwargs)
File "/home/sandish/.conda/envs/torch_rl/lib/python3.9/site-packages/tensordict/nn/common.py", line 291, in wrapper
return func(_self, tensordict, *args, **kwargs)
File "/home/sandish/rl/torchrl/objectives/a2c.py", line 503, in forward
return A2CLosses._from_tensordict(td_out)
File "/home/sandish/.conda/envs/torch_rl/lib/python3.9/site-packages/tensordict/tensorclass.py", line 327, in wrapper
raise ValueError(
ValueError: Keys from the tensordict ({'loss_entropy', 'loss_objective', 'entropy', 'loss_critic'}) must correspond to the class attributes (set()).
torchrl/objectives/a2c.py
Outdated
@property | ||
def aggregate_loss(self): | ||
return self.loss_critic + self.loss_objective + self.loss_entropy |
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.
No need to recode this
torchrl/objectives/a2c.py
Outdated
def aggregate_loss(self): | ||
result = 0.0 | ||
for key in self.__dataclass_attr__: | ||
if key.startswith("loss_"): | ||
result += getattr(self, key) | ||
return result |
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.
Should be a property
Should always return a tensor
Something like
result = torch.zeros((), device=self.device)
...
return result
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.
Missing docstring for this method.
torchrl/objectives/a2c.py
Outdated
@@ -455,7 +497,7 @@ def _cached_detach_critic_network_params(self): | |||
return self.critic_network_params.detach() | |||
|
|||
@dispatch() | |||
def forward(self, tensordict: TensorDictBase) -> TensorDictBase: | |||
def forward(self, tensordict: TensorDictBase) -> A2CLosses: |
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.
def forward(self, tensordict: TensorDictBase) -> A2CLosses: | |
def forward(self, tensordict: TensorDictBase) -> A2CLosses | TensorDictBase: |
torchrl/objectives/sac.py
Outdated
class LossContainerBase: | ||
"""ContainerBase class loss tensorclass's.""" | ||
|
||
__getitem__ = TensorDictBase.__getitem__ | ||
|
||
def aggregate_loss(self): | ||
result = 0.0 | ||
for key in self.__dataclass_attr__: | ||
if key.startswith("loss_"): | ||
result += getattr(self, key) | ||
return result | ||
|
||
|
||
@tensorclass | ||
class SACLosses(LossContainerBase): | ||
"""The tensorclass for The SACLoss Loss class.""" | ||
|
||
loss_actor: torch.Tensor | ||
loss_value: torch.Tensor | ||
loss_qvalue: torch.Tensor | ||
alpha: torch.Tensor | None = None | ||
loss_alpha: torch.Tensor | None = None | ||
entropy: torch.Tensor | None = None |
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.
ditto
torchrl/objectives/sac.py
Outdated
@@ -541,7 +581,7 @@ def out_keys(self, values): | |||
self._out_keys = values | |||
|
|||
@dispatch | |||
def forward(self, tensordict: TensorDictBase) -> TensorDictBase: | |||
def forward(self, tensordict: TensorDictBase) -> SACLosses: |
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.
def forward(self, tensordict: TensorDictBase) -> SACLosses: | |
def forward(self, tensordict: TensorDictBase) -> SACLosses | TensorDictBase: |
torchrl/objectives/sac.py
Outdated
out["loss_value"] = loss_value.mean() | ||
return TensorDict(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.
Why this change?
torchrl/objectives/td3.py
Outdated
class LossContainerBase: | ||
"""ContainerBase class loss tensorclass's.""" | ||
|
||
__getitem__ = TensorDictBase.__getitem__ | ||
|
||
def aggregate_loss(self): | ||
result = 0.0 | ||
for key in self.__dataclass_attr__: | ||
if key.startswith("loss_"): | ||
result += getattr(self, key) | ||
return result | ||
|
||
|
||
@tensorclass | ||
class TD3Losses(LossContainerBase): | ||
"""The tensorclass for The TD3 Loss class.""" | ||
|
||
loss_actor: torch.Tensor | ||
loss_qvalue: torch.Tensor | ||
target_value: torch.Tensor | None = None | ||
state_action_value_actor: torch.Tensor | None = None | ||
pred_value: torch.Tensor | None = None | ||
next_state_value: torch.Tensor | None = None |
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.
ditto
torchrl/objectives/td3.py
Outdated
@@ -453,7 +492,7 @@ def value_loss(self, tensordict): | |||
return loss_qval, metadata | |||
|
|||
@dispatch | |||
def forward(self, tensordict: TensorDictBase) -> TensorDictBase: | |||
def forward(self, tensordict: TensorDictBase) -> TD3Losses: |
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.
def forward(self, tensordict: TensorDictBase) -> TD3Losses: | |
def forward(self, tensordict: TensorDictBase) -> TD3Losses | TensorDictBase: |
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!
New classes should be manually added to the doc
See docs/source/reference/objectives.rst
The feature seems untested to me, am I right?
66fc382
to
db00e02
Compare
db00e02
to
715d4c0
Compare
@vmoens address most of your comments above, but doctests are failing with below error not caused by this PR changes.
|
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.
Great progress!
I'd like to brainstorm about naming of those classes, A2CLosses seems a bit awkward when we have A2CLoss which is a totally different thing.
I don't think we should rename "loss" in "loss_objective" as part of this PR
torchrl/objectives/a2c.py
Outdated
@@ -300,6 +322,8 @@ def __init__( | |||
if gamma is not None: | |||
raise TypeError(_GAMMA_LMBDA_DEPREC_ERROR) | |||
self.loss_critic_type = loss_critic_type | |||
self.return_tensorclass = return_tensorclass | |||
self.reduction = reduction |
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.
duplicate
@@ -32,6 +34,15 @@ | |||
VTrace, | |||
) | |||
|
|||
@tensorclass |
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.
doens't it work if we make the base class a tensorclass?
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.
Yes, It doesn't work.
torchrl/objectives/common.py
Outdated
@@ -298,7 +309,7 @@ def _compare_and_expand(param): | |||
# set the functional module: we need to convert the params to non-differentiable params | |||
# otherwise they will appear twice in parameters | |||
with params.apply( | |||
self._make_meta_params, device=torch.device("meta"), filter_empty=False | |||
self._make_meta_params, device=torch.device("meta") |
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.
why is this removed?
torchrl/objectives/dqn.py
Outdated
loss_objective: torch.Tensor | ||
loss: torch.Tensor |
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.
why two?
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.
Great progress!
I'd like to brainstorm about naming of those classes, A2CLosses seems a bit awkward when we have A2CLoss which is a totally different thing.
I don't think we should rename "loss" in "loss_objective" as part of this PR
c7cf4b9
to
bae4237
Compare
review changes
95bad71
to
e17c91e
Compare
@vmoens made changes based on your review, I still reduction is not being added to the test_cost.py file so all of the failures are related to that. |
ad2b6c3
to
8b5e0ff
Compare
Description
followup from this pull request
copy past:
We project on using https://github.com/Tensorclass to represent losses.
The advantage of tensorclass for losses instead of tensordict is that it will help us use all the features of tensordict while preserving type annotation or even completion.
Changes:
Check the out_keys of the loss;
Create a tensorclass with the respective fields;
Type the forward as returning that class (and/or a tensordict)
Add an argument to return the class in the constructor with the False value by default;
Update the docstrings (not done)
Write a little test to check that things work as expected (this test should be new and not parametrized - if we add one more parameter to the existing tests the code will be much longer and harder to follow, and the tests will run for a long time).
Types of changes
What types of changes does your code introduce? Remove all that do not apply:
Checklist
Go over all the following points, and put an
x
in all the boxes that apply.If you are unsure about any of these, don't hesitate to ask. We are here to help!