Repository navigation
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/rl/4705
Note: Links to docs will display an error until the docs builds have been completed.
|
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #4704.
One commit per problem described in the issue:
_stepchecks the done entries of the last step with_terminated_or_truncated(the helperEnvBasealready uses, which handles nested done keys) and stops if any is set. This matches the loop inGymLikeEnv._step, which breaks ondone.any().parent.step_mdp(tensordict.copy().set("next", next_tensordict)). Envs that keep their state internally behave as before; envs that read it from the tensordict (PendulumEnv, and from reading the codeBraxWrapperandJumanjiWrapper) now takeframe_skipreal steps. The copy leaves the caller's tensordict unchanged. Entries the caller preset in"next", such as the next recurrent state written by an LSTM/GRU policy, are carried over to every repeat:step_mdpdrops"next", and aTensorDictPrimerafter the frame skip would otherwise reset them.The class docstring now says that each repeat starts from the state reached so far and that the repetition stops early on done (for any element of a batched env).
Tests
Added to
TestFrameSkipTransform. The expected values come from the plain env or fromGymEnv's built-in frame skip, never from the transform.test_frame_skip_stops_at_done: the base env is done after 2 of 4 repeats; the transform must stop there with every done key set (flat and nested keys).test_transform_env_episode_end(gym):GymEnv(Pendulum, frame_skip=3)against the transform for 70 steps across the truncation at base step 200, which lands on the 2nd repeat of the 67th step.test_frame_skip_stateless_env(skip 2 and 3):PendulumEnvagainst the plain env rolled outskipsteps, and the input tensordict must be unchanged.test_frame_skip_stateless_done_on_terminal_step: a small stateless env whose done is set only on the terminal step (flat and nested keys).test_frame_skip_keeps_next_preset: a preset("next", "hidden")must survive the repeats with aTensorDictPrimerafter the frame skip.The tests of each commit fail on the code before it. The exception is the preset test, which guards the second commit's own change: it fails if the state advance is done without carrying
"next"over.Behavior notes
These are also raised in #4704.
GymLikeEnvuses (done.any()).FrameSkipTransform, e.g.Compose(StepCounter(), FrameSkipTransform(3)), now advances once per base step, so step_count goes 3, 6, 9 instead of 1, 2, 3. Nothing in the repo uses that order, and the auto-appended transform comes first.step_mdpand copy cost about 30 to 40 us per extra repeat in a local CPU timing with no episode ends. On cheap envs (ContinuousActionVecMockEnv,PendulumEnv, gymPendulum-v1) that is +19% to +27% per step withframe_skip=2and +29% to +40% withframe_skip=4; envs with a more expensive step pay a smaller share. I did not add a benchmark since this is a correctness fix, and I can look at reducing this if it matters.Testing
test/transforms,test/envs,test/test_collectors.pyandtest/libs/test_gym.pypass with gymnasium 1.4.0.test/transformspasses in a local copy of the olddeps setup: Python 3.10, torch 2.11, gym 0.13, numpy 1.26, tensordict main.TestFrameSkipTransformpasses with tensordict main and with 0.15.5.Not changed here
These are pre-existing and behave the same on main; I can open separate issues for them.
FrameSkipTransformis applied a second time on each repeat.KeyError.Motivation and Context
See #4704: on main the transform keeps stepping after the episode ends (summing rewards from past the end and possibly reporting
done=False), and on stateless envs it re-runs the same transitionframe_skiptimes.Types of changes
Checklist
I used Claude Code (Opus 5.5 xHigh) to help investigate, implement and test this change, and I reviewed all of it.