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 functionality for rendering videos within cogman, rather than within the environment #1581

Merged
merged 3 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions predicators/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def create_arg_parser(env_required: bool = True,
parser.add_argument("--make_failure_videos", action="store_true")
parser.add_argument("--make_interaction_videos", action="store_true")
parser.add_argument("--make_demo_videos", action="store_true")
parser.add_argument("--make_cogman_videos", action="store_true")
parser.add_argument("--load_approach", action="store_true")
# In the case of online learning approaches, load_approach by itself
# will try to load an approach on *every* online learning cycle.
Expand Down
21 changes: 20 additions & 1 deletion predicators/cogman.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
import logging
from typing import Callable, List, Optional, Sequence, Set

from predicators import utils
from predicators.approaches import BaseApproach
from predicators.execution_monitoring import BaseExecutionMonitor
from predicators.perception import BasePerceiver
from predicators.settings import CFG
from predicators.structs import Action, Dataset, EnvironmentTask, GroundAtom, \
InteractionRequest, InteractionResult, LowLevelTrajectory, Metrics, \
Observation, State, Task
Observation, State, Task, Video


class CogMan:
Expand All @@ -32,24 +33,38 @@ def __init__(self, approach: BaseApproach, perceiver: BasePerceiver,
self._current_goal: Optional[Set[GroundAtom]] = None
self._override_policy: Optional[Callable[[State], Action]] = None
self._termination_fn: Optional[Callable[[State], bool]] = None
self._current_env_task: Optional[EnvironmentTask] = None
self._episode_state_history: List[State] = []
self._episode_action_history: List[Action] = []
self._episode_images: Video = []
self._episode_num = -1

def reset(self, env_task: EnvironmentTask) -> None:
"""Start a new episode of environment interaction."""
logging.info("[CogMan] Reset called.")
self._episode_num += 1
task = self._perceiver.reset(env_task)
self._current_env_task = env_task
self._current_goal = task.goal
self._reset_policy(task)
self._exec_monitor.reset(task)
self._exec_monitor.update_approach_info(
self._approach.get_execution_monitoring_info())
self._episode_state_history = [task.init]
self._episode_action_history = []
self._episode_images = []
if CFG.make_cogman_videos:
imgs = self._perceiver.render_mental_images(task.init, env_task)
self._episode_images.extend(imgs)

def step(self, observation: Observation) -> Optional[Action]:
"""Receive an observation and produce an action, or None for done."""
state = self._perceiver.step(observation)
if CFG.make_cogman_videos:
assert self._current_env_task is not None
imgs = self._perceiver.render_mental_images(
state, self._current_env_task)
self._episode_images.extend(imgs)
# Replace the first step because the state was already added in reset().
if not self._episode_action_history:
self._episode_state_history[0] = state
Expand Down Expand Up @@ -86,6 +101,10 @@ def finish_episode(self, observation: Observation) -> None:
self._episode_action_history):
state = self._perceiver.step(observation)
self._episode_state_history.append(state)
if CFG.make_cogman_videos:
save_prefix = utils.get_config_path_str()
outfile = f"{save_prefix}__cogman__episode{self._episode_num}.mp4"
utils.save_video(outfile, self._episode_images)

# The methods below provide an interface to the approach. In the future,
# we may want to move some of these methods into cogman properly, e.g.,
Expand Down
8 changes: 7 additions & 1 deletion predicators/perception/base_perceiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import abc

from predicators.structs import EnvironmentTask, Observation, State, Task
from predicators.structs import EnvironmentTask, Observation, State, Task, \
Video


class BasePerceiver(abc.ABC):
Expand All @@ -20,3 +21,8 @@ def reset(self, env_task: EnvironmentTask) -> Task:
@abc.abstractmethod
def step(self, observation: Observation) -> State:
"""Produce a State given the current and past observations."""

@abc.abstractmethod
def render_mental_images(self, observation: Observation,
env_task: EnvironmentTask) -> Video:
"""Create mental images for the given observation."""
6 changes: 5 additions & 1 deletion predicators/perception/kitchen_perceiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from predicators.envs.kitchen import KitchenEnv
from predicators.perception.base_perceiver import BasePerceiver
from predicators.structs import EnvironmentTask, GroundAtom, Observation, \
State, Task
State, Task, Video


class KitchenPerceiver(BasePerceiver):
Expand Down Expand Up @@ -49,3 +49,7 @@ def step(self, observation: Observation) -> State:

def _observation_to_state(self, obs: Observation) -> State:
return KitchenEnv.state_info_to_state(obs["state_info"])

def render_mental_images(self, observation: Observation,
env_task: EnvironmentTask) -> Video:
raise NotImplementedError("Mental images not implemented for kitchen")
6 changes: 5 additions & 1 deletion predicators/perception/sokoban_perceiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from predicators.envs.sokoban import SokobanEnv
from predicators.perception.base_perceiver import BasePerceiver
from predicators.structs import EnvironmentTask, GroundAtom, Object, \
Observation, State, Task
Observation, State, Task, Video

# Each observation is a tuple of four 2D boolean masks (numpy arrays).
# The order is: free, goals, boxes, player.
Expand Down Expand Up @@ -95,3 +95,7 @@ def _get_object_name(r: int, c: int, type_name: str) -> str:

state = utils.create_state_from_dict(state_dict)
return state

def render_mental_images(self, observation: Observation,
env_task: EnvironmentTask) -> Video:
raise NotImplementedError("Mental images not implemented for sokoban")
12 changes: 11 additions & 1 deletion predicators/perception/trivial_perceiver.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""A trivial perceiver that assumes observations are already states."""

from predicators.envs import get_or_create_env
from predicators.perception.base_perceiver import BasePerceiver
from predicators.structs import EnvironmentTask, Observation, State, Task
from predicators.settings import CFG
from predicators.structs import EnvironmentTask, Observation, State, Task, \
Video


class TrivialPerceiver(BasePerceiver):
Expand All @@ -17,3 +20,10 @@ def reset(self, env_task: EnvironmentTask) -> Task:
def step(self, observation: Observation) -> State:
assert isinstance(observation, State)
return observation

def render_mental_images(self, observation: Observation,
env_task: EnvironmentTask) -> Video:
# Use the environment's render function by default.
assert isinstance(observation, State)
env = get_or_create_env(CFG.env)
return env.render_state(observation, env_task)
2 changes: 2 additions & 0 deletions tests/envs/test_sokoban.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ def test_sokoban():
imgs = env.render()
assert len(imgs) == 1
task = perceiver.reset(env_task)
with pytest.raises(NotImplementedError):
perceiver.render_mental_images(env_task.init_obs, env_task)
state = task.init
atoms = utils.abstract(state, env.predicates)
num_boxes = len({a for a in atoms if a.predicate == IsBox})
Expand Down
6 changes: 3 additions & 3 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ def test_main():
eval_traj_dir = os.path.join(parent_dir, "_fake_trajs")
sys.argv = [
"dummy", "--env", "cover", "--approach", "oracle", "--seed", "123",
"--make_test_videos", "--num_test_tasks", "1", "--video_dir",
video_dir, "--results_dir", results_dir, "--eval_trajectories_dir",
eval_traj_dir
"--make_test_videos", "--make_cogman_videos", "--num_test_tasks", "1",
"--video_dir", video_dir, "--results_dir", results_dir,
"--eval_trajectories_dir", eval_traj_dir
]
main()
# Test making videos of failures and local logging.
Expand Down
Loading