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

Environment Factory+Habitat 2.0 Code Cleanup #1401

Merged
merged 75 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
03acdf8
Fixed HRL bug
ASzot Apr 17, 2023
c286381
Allowing actions
ASzot Apr 17, 2023
2c74d33
Allowing None for rnn hidden states
ASzot Apr 29, 2023
3d38661
Fixed bug with constraints
ASzot Apr 29, 2023
ce2be9d
Nav improvements
ASzot Apr 29, 2023
f97ca99
Pddl fixes
ASzot May 7, 2023
ee048e4
Updated printing
ASzot May 10, 2023
f85aa36
Removed comment
ASzot May 10, 2023
41a5932
Profiling
ASzot May 14, 2023
6b0f3bb
More HRL fixes
ASzot May 15, 2023
9489329
Fixed bugs
ASzot May 15, 2023
c7f8ff3
Added arm init
ASzot May 18, 2023
de60c70
Performance profiling system
ASzot May 21, 2023
c258ce5
PR comments
ASzot May 22, 2023
863e567
Update habitat-lab/habitat/tasks/rearrange/multi_task/pddl_logical_ex…
ASzot May 22, 2023
39aa5ef
Update habitat-lab/habitat/tasks/rearrange/multi_task/pddl_predicate.py
ASzot May 22, 2023
add16c3
doc strings
ASzot May 22, 2023
05f138b
CI
ASzot May 23, 2023
bc5a23e
Comments
ASzot May 23, 2023
5c128d4
Update habitat-baselines/habitat_baselines/rl/hrl/hierarchical_policy.py
ASzot May 23, 2023
b684acd
Update habitat-lab/habitat/tasks/rearrange/multi_task/pddl_logical_ex…
ASzot May 23, 2023
6642340
Update habitat-lab/habitat/tasks/rearrange/multi_task/pddl_logical_ex…
ASzot May 23, 2023
13a8d6c
Comments
ASzot May 23, 2023
a92a538
Merge remote-tracking branch 'upstream/main' into hrl_fixes2
ASzot May 23, 2023
c433a15
CI
ASzot May 23, 2023
67afc58
Fixup to fixed policy
ASzot May 23, 2023
02e9675
Fixed tests
ASzot May 28, 2023
682bcb7
Fixed tests
ASzot May 28, 2023
cc96de2
Merge remote-tracking branch 'origin/main' into hrl_fixes2
ASzot May 29, 2023
1a3a599
Dataset uprade
ASzot May 30, 2023
ce76655
PDDL setup
ASzot May 30, 2023
571c486
Merge remote-tracking branch 'upstream/rearrange_v2' into hrl_fixes3
ASzot May 30, 2023
5597da7
Merged
ASzot May 30, 2023
cc41d54
merged
ASzot May 30, 2023
940bead
Fixed problem with grasping and open cab
ASzot May 31, 2023
997031c
Config options
ASzot May 31, 2023
0d0fb0c
Env factory
ASzot Jun 3, 2023
116a7ab
CI
ASzot Jun 3, 2023
205b4e4
Removed prints
ASzot Jun 4, 2023
55a51a1
obj sampling
ASzot Jun 5, 2023
63b2591
Obj sampler fixes
ASzot Jun 6, 2023
41573d3
Better kinematic mode
ASzot Jun 7, 2023
a2799c4
CI
ASzot Jun 7, 2023
99dd2d7
Fixed stats reporting
ASzot Jun 8, 2023
27cd367
removed dataset v2
ASzot Jun 8, 2023
a204d1c
removing bad print statements
ASzot Jun 8, 2023
d62d0d5
precommit
ASzot Jun 11, 2023
3738b0d
pre commit
ASzot Jun 11, 2023
b92a701
Sub in clone for robo state
ASzot Jun 14, 2023
516967b
Not always updating RNN state during eval
ASzot Jun 18, 2023
5499e6c
Added save callback
ASzot Jun 18, 2023
a4d3830
More docs
ASzot Jun 20, 2023
af9d621
Addressed PR comments
ASzot Jun 23, 2023
0d86ea0
HL and LL hidden states
ASzot Jun 25, 2023
e98ea57
Fixed hidden state issue
ASzot Jun 26, 2023
9d7217a
More flexibility around RNN hidden state size
ASzot Jun 26, 2023
6b1c0fe
Visual encoder flexibility
ASzot Jun 28, 2023
8d0d414
Fixed some logging
ASzot Jul 4, 2023
d865cbf
Merge remote-tracking branch 'upstream/main' into hrl_fixes3
ASzot Jul 4, 2023
a7f5e0d
Added GPU device ID to the dataset generator
ASzot Jul 6, 2023
2997ad0
CI
ASzot Jul 8, 2023
c6cd2fe
Tests
ASzot Jul 8, 2023
151a726
Fixed rnn hidden state issue
ASzot Jul 8, 2023
d769af5
Removed bad assert
ASzot Jul 9, 2023
5d0a742
Storage cleanup
ASzot Jul 9, 2023
7e1093d
Fixed storage args
ASzot Jul 9, 2023
7baa1cb
Rerun CI?
ASzot Jul 10, 2023
f5eee45
Merge remote-tracking branch 'upstream/main' into hrl_fixes3
ASzot Jul 11, 2023
16230d8
Maybe fixed CI
ASzot Jul 11, 2023
c793c8c
Fixed sensor overflow problem
ASzot Jul 11, 2023
f8a297b
Updated logger statement
ASzot Jul 11, 2023
b8a185a
Removed sort
ASzot Jul 11, 2023
4e03f78
Merge remote-tracking branch 'upstream/main' into hrl_fixes3
ASzot Jul 17, 2023
15301b4
Merge remote-tracking branch 'upstream/main' into hrl_fixes3
ASzot Jul 18, 2023
c4b9c3f
Merge remote-tracking branch 'upstream/main' into hrl_fixes3
ASzot Jul 19, 2023
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
113 changes: 0 additions & 113 deletions habitat-baselines/habitat_baselines/common/construct_vector_env.py

This file was deleted.

34 changes: 34 additions & 0 deletions habitat-baselines/habitat_baselines/common/env_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING

from habitat import VectorEnv

if TYPE_CHECKING:
from omegaconf import DictConfig


class VectorEnvFactory(ABC):
Copy link
Contributor

Choose a reason for hiding this comment

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

VectorEnvFactory seem to only have one implementation. Is this overengineered?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree it only has 1 implementation in the current setup. However, this makes it much easier to (1) integrate with external environments that have a custom vectorized environment implementation, (2) create custom vector env logic.

"""
Interface responsible for constructing vectorized environments used in training.
"""

@abstractmethod
def construct_envs(
self,
config: "DictConfig",
workers_ignore_signals: bool = False,
enforce_scenes_greater_eq_environments: bool = False,
is_first_rank: bool = True,
) -> VectorEnv:
"""
Setup a vectorized environment.

:param config: configs that contain num_environments as well as information
:param workers_ignore_signals: Passed to :ref:`habitat.VectorEnv`'s constructor
:param enforce_scenes_greater_eq_environments: Make sure that there are more (or equal)
:param enforce_scenes_greater_eq_environments: Make sure that there are more (or equal)
scenes than environments. This is needed for correct evaluation.
:param is_first_rank: If these environments are being constructed on the rank0 GPU.

:return: VectorEnv object created according to specification.
"""
120 changes: 120 additions & 0 deletions habitat-baselines/habitat_baselines/common/habitat_env_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Copyright (c) Meta Platforms, Inc. and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

import os
import random
from typing import TYPE_CHECKING, Any, List, Type

from habitat import ThreadedVectorEnv, VectorEnv, logger, make_dataset
from habitat.config import read_write
from habitat.gym import make_gym_from_config
from habitat_baselines.common.env_factory import VectorEnvFactory

if TYPE_CHECKING:
from omegaconf import DictConfig


class HabitatVectorEnvFactory(VectorEnvFactory):
def construct_envs(
self,
config: "DictConfig",
workers_ignore_signals: bool = False,
enforce_scenes_greater_eq_environments: bool = False,
is_first_rank: bool = True,
) -> VectorEnv:
r"""Create VectorEnv object with specified config and env class type.
To allow better performance, dataset are split into small ones for
each individual env, grouped by scenes.
"""

num_environments = config.habitat_baselines.num_environments
configs = []
dataset = make_dataset(config.habitat.dataset.type)
scenes = config.habitat.dataset.content_scenes
if "*" in config.habitat.dataset.content_scenes:
scenes = dataset.get_scenes_to_load(config.habitat.dataset)

if num_environments < 1:
raise RuntimeError("num_environments must be strictly positive")

if len(scenes) == 0:
raise RuntimeError(
"No scenes to load, multiple process logic relies on being able to split scenes uniquely between processes"
)

random.shuffle(scenes)

scene_splits: List[List[str]] = [[] for _ in range(num_environments)]
if len(scenes) < num_environments:
msg = f"There are less scenes ({len(scenes)}) than environments ({num_environments}). "
if enforce_scenes_greater_eq_environments:
logger.warn(
msg
+ "Reducing the number of environments to be the number of scenes."
)
num_environments = len(scenes)
scene_splits = [[s] for s in scenes]
else:
logger.warn(
msg
+ "Each environment will use all the scenes instead of using a subset."
)
for scene in scenes:
for split in scene_splits:
split.append(scene)
else:
for idx, scene in enumerate(scenes):
scene_splits[idx % len(scene_splits)].append(scene)
assert sum(map(len, scene_splits)) == len(scenes)

for env_index in range(num_environments):
proc_config = config.copy()
with read_write(proc_config):
task_config = proc_config.habitat
task_config.seed = task_config.seed + env_index
remove_measure_names = []
if not is_first_rank:
# Filter out non rank0_measure from the task config if we are not on rank0.
remove_measure_names.extend(
task_config.task.rank0_measure_names
)
if (env_index != 0) or not is_first_rank:
# Filter out non-rank0_env0 measures from the task config if we
# are not on rank0 env0.
remove_measure_names.extend(
task_config.task.rank0_env0_measure_names
)

task_config.task.measurements = {
k: v
for k, v in task_config.task.measurements.items()
if k not in remove_measure_names
}

if len(scenes) > 0:
task_config.dataset.content_scenes = scene_splits[
env_index
]

configs.append(proc_config)

vector_env_cls: Type[Any]
if int(os.environ.get("HABITAT_ENV_DEBUG", 0)):
logger.warn(
"Using the debug Vector environment interface. Expect slower performance."
)
vector_env_cls = ThreadedVectorEnv
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be a separate VectorEnvFactory?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so because this is controlling the VectorEnv implementation returned.

else:
vector_env_cls = VectorEnv

envs = vector_env_cls(
make_env_fn=make_gym_from_config,
env_fn_args=tuple((c,) for c in configs),
workers_ignore_signals=workers_ignore_signals,
)

if config.habitat.simulator.renderer.enable_batch_renderer:
envs.initialize_batch_renderer(config)

return envs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ class HrlDefinedSkillConfig(HabitatBaselinesBaseConfig):
@dataclass
class HierarchicalPolicyConfig(HabitatBaselinesBaseConfig):
high_level_policy: Dict[str, Any] = MISSING
# Names of the skills to not load.
ignore_skills: List[str] = field(default_factory=list)
defined_skills: Dict[str, HrlDefinedSkillConfig] = field(
default_factory=dict
)
Expand Down Expand Up @@ -383,6 +385,28 @@ class ProfilingConfig(HabitatBaselinesBaseConfig):
num_steps_to_capture: int = -1


@dataclass
class VectorEnvFactoryConfig(HabitatBaselinesBaseConfig):
"""
`_target_` points to the `VectorEnvFactory` to setup the vectorized
environment. Defaults to the Habitat vectorized environment setup.
"""

_target_: str = (
"habitat_baselines.common.habitat_env_factory.HabitatEnvFactory"
)


@dataclass
class HydraCallbackConfig(HabitatBaselinesBaseConfig):
"""
Generic callback option for Hydra. Used to create the `_target_` class or
call the `_target_` method.
"""

_target_: Optional[str] = None


Copy link
Contributor

Choose a reason for hiding this comment

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

Should these two be merged into a single class? Like InstantiationConfig? It seems they have the same attribute.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so because I want the default to be different.

@dataclass
class HabitatBaselinesConfig(HabitatBaselinesBaseConfig):
# task config can be a list of configs like "A.yaml,B.yaml"
Expand Down Expand Up @@ -413,6 +437,8 @@ class HabitatBaselinesConfig(HabitatBaselinesBaseConfig):
log_file: str = "train.log"
force_blind_policy: bool = False
verbose: bool = True
# Creates the vectorized environment.
vector_env_factory: VectorEnvFactoryConfig = VectorEnvFactoryConfig()
Copy link
Contributor

Choose a reason for hiding this comment

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

why not have this be a string? Is it because we need to have _target_ to get Hydra boilerplate?

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, it is so hydra.utils.instantiate will work.

eval_keys_to_include_in_name: List[str] = field(default_factory=list)
# For our use case, the CPU side things are mainly memory copies
# and nothing of substantive compute. PyTorch has been making
Expand All @@ -430,6 +456,13 @@ class HabitatBaselinesConfig(HabitatBaselinesBaseConfig):
load_resume_state_config: bool = True
eval: EvalConfig = EvalConfig()
profiling: ProfilingConfig = ProfilingConfig()
# Whether to log the infos that are only logged to a single process to the
# CLI along with the other metrics.
should_log_single_proc_infos: bool = False
Copy link
Contributor

Choose a reason for hiding this comment

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

docstring

# Called every time a checkpoint is saved.
# Function signature: fn(save_file_path: str) -> None
# If not specified, there is no callback.
on_save_ckpt_callback: Optional[HydraCallbackConfig] = None


@dataclass
Expand Down
15 changes: 11 additions & 4 deletions habitat-baselines/habitat_baselines/rl/hrl/hierarchical_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,19 @@ def __init__(
# Can map multiple skills to the same underlying skill controller.
self._skill_redirects: Dict[int, int] = {}

if "rearrange_stop" not in action_space.spaces:
raise ValueError("Hierarchical policy requires the stop action")
self._stop_action_idx, _ = find_action_range(
action_space, "rearrange_stop"
)

self._pddl = self._create_pddl(full_config, config)
self._create_skills(
dict(config.hierarchical_policy.defined_skills),
{
k: v
for k, v in config.hierarchical_policy.defined_skills.items()
if k not in config.hierarchical_policy.ignore_skills
},
observation_space,
action_space,
full_config,
Expand All @@ -98,9 +108,6 @@ def __init__(
observation_space,
action_space,
)
self._stop_action_idx, _ = find_action_range(
action_space, "rearrange_stop"
)
first_idx: Optional[int] = None

# Remap all the Noop skills to the same underlying skill so all the
Expand Down
9 changes: 2 additions & 7 deletions habitat-baselines/habitat_baselines/rl/hrl/skills/nn_skill.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def from_config(
)
except FileNotFoundError as e:
raise FileNotFoundError(
"Could not load neural network weights for skill."
f"Could not load neural network weights for skill from ckpt {config.load_ckpt_file}"
) from e

policy_cfg = ckpt_dict["config"]
Expand Down Expand Up @@ -224,12 +224,7 @@ def from_config(
)
if len(ckpt_dict) > 0:
try:
actor_critic.load_state_dict(
{ # type: ignore
k[len("actor_critic.") :]: v
for k, v in ckpt_dict["state_dict"].items()
}
)
actor_critic.load_state_dict(ckpt_dict["state_dict"])

except Exception as e:
raise ValueError(
Expand Down
2 changes: 1 addition & 1 deletion habitat-baselines/habitat_baselines/rl/hrl/skills/place.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def _mask_pick(self, action, observations):
is_not_holding = 1 - observations[IsHoldingSensor.cls_uuid].view(-1)
for i in torch.nonzero(is_not_holding):
# Do not regrasp the object once it is released.
action[i, self._grip_ac_idx] = -1.0
action.actions[i, self._grip_ac_idx] = -1.0
return action

def _is_skill_done(
Expand Down
Loading