Download gym_util/multistep_wrapper.py from ducido/diffusion_policy_gbc: direct link, hf CLI and curl.
- Browser
- Download file 6.33 kB
-
https://huggingface.co/ducido/diffusion_policy_gbc/resolve/main/gym_util/multistep_wrapper.py
- Command line
-
hf download hf://ducido/diffusion_policy_gbc/gym_util/multistep_wrapper.py
-
curl -L -o multistep_wrapper.py https://huggingface.co/ducido/diffusion_policy_gbc/resolve/main/gym_util/multistep_wrapper.py
6.33 kB
| import gym | |
| from gym import spaces | |
| import numpy as np | |
| from collections import defaultdict, deque | |
| import dill | |
| def stack_repeated(x, n): | |
| return np.repeat(np.expand_dims(x,axis=0),n,axis=0) | |
| def repeated_box(box_space, n): | |
| return spaces.Box( | |
| low=stack_repeated(box_space.low, n), | |
| high=stack_repeated(box_space.high, n), | |
| shape=(n,) + box_space.shape, | |
| dtype=box_space.dtype | |
| ) | |
| def repeated_space(space, n): | |
| if isinstance(space, spaces.Box): | |
| return repeated_box(space, n) | |
| elif isinstance(space, spaces.Dict): | |
| result_space = spaces.Dict() | |
| for key, value in space.items(): | |
| result_space[key] = repeated_space(value, n) | |
| return result_space | |
| else: | |
| raise RuntimeError(f'Unsupported space type {type(space)}') | |
| def take_last_n(x, n): | |
| x = list(x) | |
| n = min(len(x), n) | |
| return np.array(x[-n:]) | |
| def dict_take_last_n(x, n): | |
| result = dict() | |
| for key, value in x.items(): | |
| result[key] = take_last_n(value, n) | |
| return result | |
| def aggregate(data, method='max'): | |
| if method == 'max': | |
| # equivalent to any | |
| return np.max(data) | |
| elif method == 'min': | |
| # equivalent to all | |
| return np.min(data) | |
| elif method == 'mean': | |
| return np.mean(data) | |
| elif method == 'sum': | |
| return np.sum(data) | |
| else: | |
| raise NotImplementedError() | |
| def stack_last_n_obs(all_obs, n_steps): | |
| assert(len(all_obs) > 0) | |
| all_obs = list(all_obs) | |
| result = np.zeros((n_steps,) + all_obs[-1].shape, | |
| dtype=all_obs[-1].dtype) | |
| start_idx = -min(n_steps, len(all_obs)) | |
| result[start_idx:] = np.array(all_obs[start_idx:]) | |
| if n_steps > len(all_obs): | |
| # pad | |
| result[:start_idx] = result[start_idx] | |
| return result | |
| def get_env_domain_for_multistep_wrapper(env): | |
| if env.__class__.__name__ == "VideoRecordingWrapper": | |
| if "robomimic" in env.env.__class__.__name__.lower(): | |
| env_domain = "robomimic" | |
| elif "pusht" in env.env.__class__.__name__.lower(): | |
| env_domain = "pusht" | |
| elif "kitchen" in env.env.__class__.__name__.lower(): | |
| env_domain = "kitchen" | |
| else: | |
| raise NotImplementedError() | |
| else: | |
| if "robomimic" in env.__class__.__name__.lower(): | |
| env_domain = "robomimic" | |
| elif "pusht" in env.__class__.__name__.lower(): | |
| env_domain = "pusht" | |
| elif "kitchen" in env.__class__.__name__.lower(): | |
| env_domain = "kitchen" | |
| else: | |
| raise NotImplementedError() | |
| return env_domain | |
| class MultiStepWrapper(gym.Wrapper): | |
| def __init__(self, | |
| env, | |
| n_obs_steps, | |
| n_action_steps, | |
| max_episode_steps=None, | |
| reward_agg_method='max' | |
| ): | |
| super().__init__(env) | |
| self._action_space = repeated_space(env.action_space, n_action_steps) | |
| self._observation_space = repeated_space(env.observation_space, n_obs_steps) | |
| self.max_episode_steps = max_episode_steps | |
| self.n_obs_steps = n_obs_steps | |
| self.n_action_steps = n_action_steps | |
| self.reward_agg_method = reward_agg_method | |
| self.obs = deque(maxlen=n_obs_steps+1) | |
| self.reward = list() | |
| self.done = list() | |
| self.info = defaultdict(lambda : deque(maxlen=n_obs_steps+1)) | |
| self.all_infos = list() | |
| self.step_elapsed = 0 | |
| def reset(self): | |
| """Resets the environment using kwargs.""" | |
| obs = super().reset() | |
| self.step_elapsed = 0 | |
| self.obs = deque([obs], maxlen=self.n_obs_steps+1) | |
| self.reward = list() | |
| self.done = list() | |
| self.info = defaultdict(lambda : deque(maxlen=self.n_obs_steps+1)) | |
| self.all_infos = list() | |
| obs = self._get_obs(self.n_obs_steps) | |
| env_domain = get_env_domain_for_multistep_wrapper(self.env) | |
| if env_domain == "robomimic": | |
| init_info = self.env.env.env.get_state() | |
| success = self.env.env.env.is_success()["task"] | |
| init_info.update({"success": float(success)}) | |
| self.all_infos.append(init_info) | |
| return obs | |
| def step(self, action): | |
| """ | |
| actions: (n_action_steps,) + action_shape | |
| """ | |
| for act in action: | |
| if len(self.done) > 0 and self.done[-1]: | |
| # termination | |
| break | |
| observation, reward, done, info = super().step(act) | |
| self.step_elapsed += 1 | |
| self.obs.append(observation) | |
| self.reward.append(reward) | |
| if (self.max_episode_steps is not None) \ | |
| and (len(self.reward) >= self.max_episode_steps): | |
| # truncation | |
| done = True | |
| self.done.append(done) | |
| self._add_info(info) | |
| self.all_infos.append(info) | |
| observation = self._get_obs(self.n_obs_steps) | |
| reward = aggregate(self.reward, self.reward_agg_method) | |
| done = aggregate(self.done, 'max') | |
| info = dict_take_last_n(self.info, self.n_obs_steps) | |
| return observation, reward, done, info | |
| def _get_obs(self, n_steps=1): | |
| """ | |
| Output (n_steps,) + obs_shape | |
| """ | |
| assert(len(self.obs) > 0) | |
| if isinstance(self.observation_space, spaces.Box): | |
| return stack_last_n_obs(self.obs, n_steps) | |
| elif isinstance(self.observation_space, spaces.Dict): | |
| result = dict() | |
| for key in self.observation_space.keys(): | |
| result[key] = stack_last_n_obs( | |
| [obs[key] for obs in self.obs], | |
| n_steps | |
| ) | |
| return result | |
| else: | |
| raise RuntimeError('Unsupported space type') | |
| def _add_info(self, info): | |
| for key, value in info.items(): | |
| self.info[key].append(value) | |
| def get_rewards(self): | |
| return self.reward | |
| def get_attr(self, name): | |
| return getattr(self, name) | |
| def run_dill_function(self, dill_fn): | |
| fn = dill.loads(dill_fn) | |
| return fn(self) | |
| def get_infos(self): | |
| result = dict() | |
| for k, v in self.info.items(): | |
| result[k] = list(v) | |
| return result | |
| def get_all_infos(self): | |
| return self.all_infos | |