Repository navigation
Conversation
MultiOneHot.__getitem__ rebuilt the spec without its mask, so an indexed masked MultiOneHot spec samples outcomes that the mask excludes and accepts them in is_in. OneHot.__getitem__ indexed the mask with the index meant for the batch dims. The mask has one more dim than the batch, the outcome dim, so an index with an ellipsis, such as spec[..., 1], indexed the outcome dim of the mask instead of the last batch dim. It raised "Cannot expand mask to the desired shape", or, when the number of outcomes equals the last batch dim, silently gave the indexed spec a wrong mask. Composite[..., i] goes through the same path for its OneHot leaves. Index the mask with the outcome dim moved in front of the batch dims, so that the index, ellipsis included, only spans the batch dims, and pass the result on in both classes.
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/rl/4635
Note: Links to docs will display an error until the docs builds have been completed.
|
|
Hi @kjgggggg! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
5283220 to
1a53248
Compare
Description
Indexing a masked
MultiOneHotspec drops its mask, and indexing a maskedOneHotspec with an ellipsis indexes the wrong dim of the mask:On
main,spec[0].mask is NoneprintsTrue(sospec[0].rand()draws from all outcomes) and both ellipsis indexings raiseRuntimeError: Cannot expand mask to the desired shape.. When the number of outcomes equals the last batch dim,OneHot(4, shape=(3, 4, 4), mask=m)[..., 1]does not raise but getsm[..., 1], a slice along the outcome dim, as its mask. With this PR,spec[0].maskismask[0], andspec[..., 1].maskis the mask of the batch elements[:, 1].Causes, in
torchrl/data/tensor_specs.py:MultiOneHot.__getitem__rebuilds the spec without passingmask.OneHot.__getitem__computes the new shape with_shape_indexing(self.shape[:-1], idx), which never indexes the last (outcome) dim, but indexes the mask withself.mask[idx]. The mask has the outcome dim as its last dim, so an ellipsis inidxexpands up to the outcome dim instead of the last batch dim.Composite.__getitem__forwards the index to its leaves, so a composite spec with a maskedOneHotleaf fails the same way.Fix: a helper
_index_outcome_maskmoves the outcome dim of the mask in front, applies(slice(None), *idx)so that the index only spans the batch dims, and moves the outcome dim back.OneHot.__getitem__uses it, andMultiOneHot.__getitem__now passes its indexed mask on.Categorical(whose mask has the same layout) is left alone here, since #4624 changes its__getitem__;MultiCategorical.__getitem__also drops its mask, but it lets the index reach its last (sub-action) dim, so its mask cannot be indexed the same way and is left for a separate change.Tests:
test_indexing_preserves_mask(8 indices, among which ellipses,None, slices and a tensor, forOneHotandMultiOneHot): the indexed spec has the mask obtained by indexing each outcome of the original mask as a tensor of the batch shape, and its samples are the only allowed outcomes. Onmain, all 8MultiOneHotcases and the 2 ellipsisOneHotcases fail; the 6 otherOneHotcases pass.python -m pytest test/test_specs.py -n 4: 1836 passed, 9 skipped.python -m pytest test/test_specs.py test/envs test/transforms test/modules test/test_exploration.py -n 6(CPU): 9060 passed, 1022 skipped, 1 failed; the failure,test/envs/test_parallel.py::TestLibThreading::test_auto_num_threads, comes fromOMP_NUM_THREADS=2, which this run set (it fails the same way on the branch with that variable and passes without it:TestLibThreading2 passed). Same command onmain: 9045 passed, 1022 skipped.ufmt checkandflake8 --config=setup.cfg(pre-commit versions) pass on the changed files.Motivation and Context
An indexed action spec must not enable actions the mask forbids, and indexing with an ellipsis must work on masked specs as it does on unmasked ones.
close #4632
Types of changes
Checklist