-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgym.py
More file actions
209 lines (175 loc) · 6.36 KB
/
Copy pathgym.py
File metadata and controls
209 lines (175 loc) · 6.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import gymnasium as gym
import collections
import numpy as np
import torch
import diffusion_policy
import pickle
import gzip
import os
import argparse
import torch.nn as nn
import mani_skill2.utils.sapien_utils as utils
import mani_skill2.envs
from models.base_models.vision_encoder import get_resnet, replace_bn_with_gn
from models.base_models.ConditionalUnet1D import ConditionalUnet1D
from diffusers.schedulers.scheduling_ddpm import DDPMScheduler
from diffusers.training_utils import EMAModel
from diffusers.optimization import get_scheduler
from tqdm.auto import tqdm
from models.datasets.image_dataset import normalize_data, unnormalize_data
from mani_skill2.agents.robots.panda import Panda
# from mani_skill2.envs.tasks.tabletop import TurnFaucetEnv
# def register_adapted_envs():
# # Register AdaptedTurnFaucetEnv
# gym.envs.registration.register(
# id='AdaptedTurnFaucet-v1',
# entry_point='ManiSkill.data_collection.adapted_turn_faucet_env:AdaptedTurnFaucetEnv',
# max_episode_steps=200,
# )
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("-e", "--env-id", type=str, default="TurnFaucet-v0")
parser.add_argument("-o", "--obs-mode", type=str, default="rgbd")
parser.add_argument("-r", "--robot-uid", type=str, default="panda", help="Robot setups supported are ['panda']")
parser.add_argument("--object-id", type=str, default=None)
args, opts = parser.parse_known_args()
return args
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# # Register Adapted Envs
# register_adapted_envs()
# Parse command line arguments
args = parse_args()
# Create gym environment
env = gym.make(
args.env_id,
# num_envs=1,
obs_mode="rgbd",
control_mode="pd_joint_pos", # there is also "pd_joint_delta_pos", ...
render_mode="human"
)
ckpt_path = "models/checkpoints/ema_nets_2024-07-09_17-14-43.pth"
print("... read data")
path = "demos/rigid_body/TurnFaucet-v0"
data_file = os.path.join(path, 'stats.gzip')
f = gzip.open(data_file,'rb')
stats = pickle.load(f)
# parameters
pred_horizon = 16
obs_horizon = 2
action_horizon = 8
#|o|o| observations: 2
#| |a|a|a|a|a|a|a|a| actions executed: 8
#|p|p|p|p|p|p|p|p|p|p|p|p|p|p|p|p| actions predicted: 16
num_diffusion_iters = 100
noise_scheduler = DDPMScheduler(
num_train_timesteps=num_diffusion_iters,
# the choise of beta schedule has big impact on performance
# we found squared cosine works the best
beta_schedule='squaredcos_cap_v2',
# clip output to [-1,1] to improve stability
clip_sample=True,
# our network predicts noise (instead of denoised action)
prediction_type='epsilon'
)
vision_encoder = get_resnet('resnet18')
# IMPORTANT!
# replace all BatchNorm with GroupNorm to work with EMA
# performance will tank if you forget to do this!
vision_encoder = replace_bn_with_gn(vision_encoder)
# ResNet18 has output dim of 512
vision_feature_dim = 512
# agent_pos is 2 dimensional
lowdim_obs_dim = 18
# observation feature has 514 dims in total per step
obs_dim = vision_feature_dim + lowdim_obs_dim
action_dim = 8
# create network object
noise_pred_net = ConditionalUnet1D(
input_dim=action_dim,
global_cond_dim=obs_dim*obs_horizon
)
# the final arch has 2 parts
nets = nn.ModuleDict({
'vision_encoder': vision_encoder,
'noise_pred_net': noise_pred_net
})
state_dict = torch.load(ckpt_path)
ema_nets = nets
ema_nets.load_state_dict(state_dict)
ema_nets.to(device)
# Reset environment & run it
obs, _ = env.reset(seed=0, options=dict(model_id=args.object_id)) # reset with a seed for determinism
# keep a queue of last 2 steps of observations
obs_deque = collections.deque(
[obs] * obs_horizon, maxlen=obs_horizon)
# save visualization and rewards
rewards = list()
done = False
step_idx = 0
print(obs['extra'].keys())
done = False
while not done:
B = 1
# stack the last obs_horizon number of observations
images = np.stack([x["image"]["hand_camera"]["rgb"] for x in obs_deque])
agent_poses = np.stack([np.concatenate((x["agent"]["qpos"], x["agent"]["qvel"])).flatten() for x in obs_deque])
print(agent_poses)
# normalize observation
nagent_poses = normalize_data(agent_poses, stats=stats['agent_pos'])
# images are already normalized to [0,1]
nimages = images
nimages = nimages.reshape(obs_horizon, 3, 128, 128)
# device transfer
nimages = torch.from_numpy(nimages).to(device, dtype=torch.float32)
# (2,3,96,96)
nagent_poses = torch.from_numpy(nagent_poses).to(device, dtype=torch.float32)
# (2,2)
# infer action
with torch.no_grad():
# get image features
image_features = ema_nets['vision_encoder'](nimages)
# (2,512)
# concat with low-dim observations
obs_features = torch.cat([image_features, nagent_poses], dim=-1)
# reshape observation to (B,obs_horizon*obs_dim)
obs_cond = obs_features.unsqueeze(0).flatten(start_dim=1)
# initialize action from Guassian noise
noisy_action = torch.randn(
(B, pred_horizon, action_dim), device=device)
naction = noisy_action
# init scheduler
noise_scheduler.set_timesteps(num_diffusion_iters)
for k in noise_scheduler.timesteps:
# predict noise
noise_pred = ema_nets['noise_pred_net'](
sample=naction,
timestep=k,
global_cond=obs_cond
)
# inverse diffusion step (remove noise)
naction = noise_scheduler.step(
model_output=noise_pred,
timestep=k,
sample=naction
).prev_sample
# unnormalize action
naction = naction.detach().to('cpu').numpy()
# (B, pred_horizon, action_dim)
naction = naction[0]
action_pred = unnormalize_data(naction, stats=stats['action'])
# only take action_horizon number of actions
start = obs_horizon - 1
end = start + action_horizon
action = action_pred[start:end,:]
# (action_horizon, action_dim)
# execute action_horizon number of steps
# without replanning
for i in range(len(action)):
# stepping env
obs, reward, done, _, info = env.step(action[i])
# save observations
obs_deque.append(obs)
# and reward/vis
rewards.append(reward)
env.render() # a display is required to render
env.close()