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

Add save_video util and deprecate RecordVideo in favor of it #3016

Merged
merged 9 commits into from
Aug 29, 2022

Conversation

younik
Copy link
Contributor

@younik younik commented Aug 2, 2022

This PR adds a deprecation warning to RecordVideo, in favor of a cleaner util function https://github.com/younik/gym/blob/record-video/gym/utils/save_video.py

See also #2905

Sample usage:

import gym
from gym.utils.save_video import save_video

env = gym.make("MyEnv", render_mode="rgb_array")

env.reset()
step_starting_index = 0
episode_index = 0
for step_index in range(199):
    action = env.action_space.sample()
    _, _, done, _ = env.step(action)

    if done:
        save_video(
             env.render(), 
             "videos", 
             fps=env.metadata["render_fps"], 
             step_starting_index=step_starting_index, 
             episode_index=episode_index
        )
        step_starting_index = step_index + 1
        episode_index += 1
        env.reset()

env.close()

Copy link
Contributor

@pseudo-rnd-thoughts pseudo-rnd-thoughts left a comment

Choose a reason for hiding this comment

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

Generally looks good, I added two comments for minor code changes

gym/utils/save_video.py Outdated Show resolved Hide resolved
tests/utils/test_save_video.py Outdated Show resolved Hide resolved
@younik younik marked this pull request as ready for review August 2, 2022 13:07
@vwxyzjn
Copy link
Contributor

vwxyzjn commented Aug 2, 2022

Thanks @younik for preparing the PR. What is the motivation for this change and why is using the save_video function cleaner? It looks to me save_video only adds more boilerplate code to the learning code: we need to maintain step_starting_idx and episode_idx and probably a scheduler logic to not record every episode.

Deprecating RecordVideo should perhaps serve a practical purpose.

Args:
frames (List[RenderFrame]): A list of frames to compose the video.
video_folder (str): The folder where the recordings will be stored
episode_trigger: Function that accepts an integer and returns ``True`` iff a recording should be started at this episode
Copy link
Contributor

Choose a reason for hiding this comment

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

I am very confused - why would episode_trigger still be here? It seems strange when users execute save_video the videos might not be saved…

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the beginning, the expected type of frames was a List of episodes, where an episode is a List of frames.
Talking with @pseudo-rnd-thoughts, we agree it is simpler as it is now, with frames as a List of frames of the same episode.

For how it is right now, yes, we can drop episode_trigger and the user can just do it with an if statement.
Notice that it still can happen that save_video doesn't save anything depending on step_trigger

... _, _, done, _ = env.step(action)
... if done:
... save_video(
... env.render(),
Copy link
Contributor

Choose a reason for hiding this comment

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

It looks like here only calls env.render() when the env is done. Does this mean when calling env = gym.make("FrozenLake-v1", render_mode="rgb_array") each frame is rendered and cached? If this is the case this could be an undesirable bottleneck — we might only keep the rendered frames of a few episodes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, with the current Render API env.render() returns the list of frames of the whole episode when the mode is rgb_array; old-like behavior can be obtained with single_rgb_array.

When you call render() or reset(), the frame list is cleaned

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I am struggling to understand this. If I don’t want to render every frame, how can I achieve it with the current API? What is the old-like behavior with single_rgb_array?

Copy link
Contributor Author

@younik younik Aug 3, 2022

Choose a reason for hiding this comment

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

If you want to render a single frame representing the current state, you can achieve it with single_rgb_array, thus similar to before:

env = gym.make("MyEnv", render_mode="single_rgb_array")
env.reset()

for _ in range(n_steps):
    env.step(...)
    env.render()  # single frame

env.close()

Otherwise, with rgb_array:

env = gym.make("MyEnv", render_mode="rgb_array")
env.reset()

for _ in range(n_steps):
    _, _, done, _ = env.step(...)
   if done:
      break

env.render()  # List of all frames
env.close()

@younik
Copy link
Contributor Author

younik commented Aug 2, 2022

Thanks @younik for preparing the PR. What is the motivation for this change and why is using the save_video function cleaner? It looks to me save_video only adds more boilerplate code to the learning code: we need to maintain step_starting_idx and episode_idx and probably a scheduler logic to not record every episode.

Deprecating RecordVideo should perhaps serve a practical purpose.

Hello, yes, this adds more boilerplate to user code, on the other side, save_video function is clearer than RecordVideo and fits better with the new behavior of rgb_array.

@vwxyzjn
Copy link
Contributor

vwxyzjn commented Aug 11, 2022

Could we do both? I think having the save_video as a low-level API would be helpful, but RecordVideo should be a no-brainer utility to most researchers.

@younik younik mentioned this pull request Aug 14, 2022
@younik
Copy link
Contributor Author

younik commented Aug 18, 2022

Could we do both? I think having the save_video as a low-level API would be helpful, but RecordVideo should be a no-brainer utility to most researchers.

Sure, I updated VideoRecorder to use moviepy on the other PR, thus it is easy to see the differences. For me, we can keep both, or stick with one

@pseudo-rnd-thoughts
Copy link
Contributor

Personally, I think we should have both.
The wrapper for ease of use and a separate function for users who want more control

Copy link
Contributor

@vwxyzjn vwxyzjn left a comment

Choose a reason for hiding this comment

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

LGTM

@jkterry1 jkterry1 merged commit 2a9853f into openai:master Aug 29, 2022
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.

4 participants