33from __future__ import annotations
44
55import datetime
6- import importlib
76import os
8- import pkgutil
97import sys
108from pathlib import Path
119
1614ROOT_DIR = Path (__file__ ).parent .parent
1715sys .path .append (str (ROOT_DIR ))
1816
17+ from unilab .training import create_env , ensure_registries , get_log_root , render_play_mode
1918from unilab .utils .experiment_tracking import ExperimentTracker
2019
2120
22- def ensure_registries ():
23- for pkg_name in (
24- "unilab.envs.locomotion" ,
25- "unilab.envs.manipulation" ,
26- "unilab.envs.motion_tracking" ,
27- ):
28- try :
29- package = importlib .import_module (pkg_name )
30- if hasattr (package , "__path__" ):
31- for _ , name , _ in pkgutil .walk_packages (package .__path__ , package .__name__ + "." ):
32- try :
33- importlib .import_module (name )
34- except Exception :
35- pass
36- except ImportError :
37- pass
38-
39-
4021def build_appo_runner_kwargs (
4122 cfg : DictConfig ,
4223 env_cfg_override : dict | None ,
@@ -68,79 +49,52 @@ def run_motrix_play_loop(
6849 play_env_num : int ,
6950 num_steps : int | None = None ,
7051) -> None :
71- import time
72-
7352 import numpy as np
7453 from tensordict import TensorDict
7554
7655 if env .state is None :
7756 env .init_state ()
78- env ._backend .init_renderer ()
79-
80- env_indices = np .arange (play_env_num , dtype = np .int32 )
81- obs_out , _ = env .reset (env_indices )
82- obs_np = np .asarray (obs_out ["obs" ], dtype = np .float32 )
83-
84- last_render_time = time .perf_counter ()
85- render_dt = 1.0 / 60.0
86- steps_run = 0
8757
8858 with torch .inference_mode ():
89- while num_steps is None or steps_run < num_steps :
90- obs_torch = torch .from_numpy (obs_np ).to (device )
91- td = TensorDict ({"policy" : obs_torch }, batch_size = play_env_num )
92- actions_torch = actor (td )
93- actions_np = actions_torch .cpu ().numpy ().astype (np .float32 )
94- state = env .step (actions_np )
95- obs_np = np .asarray (state .obs ["obs" ], dtype = np .float32 )
96-
97- current_time = time .perf_counter ()
98- elapsed = current_time - last_render_time
99- if elapsed < render_dt :
100- time .sleep (render_dt - elapsed )
101- last_render_time = time .perf_counter ()
102-
103- env ._backend .render ()
104- steps_run += 1
59+ render_play_mode (
60+ env ,
61+ sim_backend = "motrix" ,
62+ num_steps = num_steps ,
63+ initialize = lambda : np .asarray (
64+ env .reset (np .arange (play_env_num , dtype = np .int32 ))[0 ]["obs" ],
65+ dtype = np .float32 ,
66+ ),
67+ step = lambda obs_np : np .asarray (
68+ env .step (
69+ actor (
70+ TensorDict (
71+ {"policy" : torch .from_numpy (obs_np ).to (device )}, batch_size = play_env_num
72+ )
73+ )
74+ .cpu ()
75+ .numpy ()
76+ .astype (np .float32 )
77+ ).obs ["obs" ],
78+ dtype = np .float32 ,
79+ ),
80+ )
10581
10682
10783def resolve_appo_checkpoint_path (
10884 base_log_dir : str | Path ,
10985 load_run : str ,
11086) -> tuple [str | None , str | None ]:
111- base_log_dir = str ( base_log_dir )
87+ from unilab . training import resolve_checkpoint_path
11288
113- if load_run == "-1" :
114- if not os .path .exists (base_log_dir ):
115- return None , None
116- all_runs = sorted (
117- [d for d in os .listdir (base_log_dir ) if os .path .isdir (os .path .join (base_log_dir , d ))]
118- )
119- if not all_runs :
120- return None , None
121- candidate_dir = os .path .join (base_log_dir , all_runs [- 1 ])
122- elif os .path .isdir (load_run ):
123- candidate_dir = load_run
124- elif os .path .isfile (load_run ):
125- return load_run , os .path .dirname (load_run )
126- else :
127- candidate_dir = os .path .join (base_log_dir , load_run )
128- if not os .path .isdir (candidate_dir ):
129- return None , None
130-
131- model_files = [
132- f for f in os .listdir (candidate_dir ) if f .startswith ("model_" ) and f .endswith (".pt" )
133- ]
134- if not model_files :
135- return None , None
136-
137- model_files .sort (key = lambda x : int (x .split ("_" )[1 ].split ("." )[0 ]))
138- return os .path .join (candidate_dir , model_files [- 1 ]), candidate_dir
89+ checkpoint_path , checkpoint_dir = resolve_checkpoint_path (base_log_dir , load_run , suffix = ".pt" )
90+ return (
91+ str (checkpoint_path ) if checkpoint_path is not None else None ,
92+ str (checkpoint_dir ) if checkpoint_dir is not None else None ,
93+ )
13994
14095
14196def _get_log_root (cfg : DictConfig ) -> str :
142- """Get log root directory from algo_log_name config."""
143- return str (Path (ROOT_DIR ) / "logs" / cfg .algo .algo_log_name )
97+ return str (get_log_root (ROOT_DIR , cfg ))
14498
14599
146100def play_appo (cfg : DictConfig , rl_cfg : dict ) -> str | None :
@@ -149,7 +103,6 @@ def play_appo(cfg: DictConfig, rl_cfg: dict) -> str | None:
149103 from rsl_rl .utils import resolve_callable
150104 from tensordict import TensorDict
151105
152- from unilab .base import registry
153106 from unilab .utils .reward_utils import extract_reward_config
154107 from unilab .utils .rsl_rl_compat import convert_config_v3_to_v4 , is_rsl_rl_v4 , is_rsl_rl_v5
155108
@@ -164,10 +117,9 @@ def play_appo(cfg: DictConfig, rl_cfg: dict) -> str | None:
164117 )
165118 print (f"Using device for play: { device } " )
166119
167- env = registry . make (
168- cfg . training . task_name ,
120+ env = create_env (
121+ cfg ,
169122 num_envs = cfg .training .play_env_num ,
170- sim_backend = cfg .training .sim_backend ,
171123 env_cfg_override = env_cfg_override ,
172124 )
173125 from unilab .utils .obs_utils import get_obs_dims
@@ -231,47 +183,46 @@ def play_appo(cfg: DictConfig, rl_cfg: dict) -> str | None:
231183 raise
232184 return None
233185
234- import mediapy as media
235-
236- from unilab .utils import render_many
237-
238186 output_video = os .path .join (load_path_dir , "play_video.mp4" )
239187 print (f"Rendering video to { output_video } ..." )
240188
241189 if env .state is None :
242190 env .init_state ()
243- env_indices = np .arange (cfg .training .play_env_num , dtype = np .int32 )
244- obs_out , _ = env .reset (env_indices )
245- obs_np = np .asarray (obs_out ["obs" ], dtype = np .float32 )
246-
247- state_list = []
248191 num_steps = int (getattr (cfg .training , "play_steps" , 1000 ))
249192
250193 print ("Collecting physics states..." )
251194 with torch .inference_mode ():
252- for _ in range (num_steps ):
253- obs_torch = torch .from_numpy (obs_np ).to (device )
254- td = TensorDict ({"policy" : obs_torch }, batch_size = cfg .training .play_env_num )
255- actions_torch = actor (td )
256- actions_np = actions_torch .cpu ().numpy ().astype (np .float32 )
257- state = env .step (actions_np )
258- obs_np = np .asarray (state .obs ["obs" ], dtype = np .float32 )
259- state_list .append (np .asarray (env ._backend .get_physics_state (), dtype = np .float32 ).copy ())
260-
261- print ("Rendering frames..." )
262- frames = render_many .render_states_get_frames (
263- state_list ,
264- env .cfg .model_file ,
265- width = 1280 ,
266- height = 720 ,
267- camera_id = - 1 ,
268- cam_distance = cfg .training .cam_distance ,
269- cam_elevation = cfg .training .cam_elevation ,
270- cam_azimuth = cfg .training .cam_azimuth ,
271- )
272-
195+ render_play_mode (
196+ env ,
197+ sim_backend = cfg .training .sim_backend ,
198+ num_steps = num_steps ,
199+ output_video = output_video ,
200+ initialize = lambda : np .asarray (
201+ env .reset (np .arange (cfg .training .play_env_num , dtype = np .int32 ))[0 ]["obs" ],
202+ dtype = np .float32 ,
203+ ),
204+ step = lambda obs_np : np .asarray (
205+ env .step (
206+ actor (
207+ TensorDict (
208+ {"policy" : torch .from_numpy (obs_np ).to (device )},
209+ batch_size = cfg .training .play_env_num ,
210+ )
211+ )
212+ .cpu ()
213+ .numpy ()
214+ .astype (np .float32 )
215+ ).obs ["obs" ],
216+ dtype = np .float32 ,
217+ ),
218+ frame_state_getter = lambda : env ._backend .get_physics_state (),
219+ camera_kwargs = {
220+ "cam_distance" : cfg .training .cam_distance ,
221+ "cam_elevation" : cfg .training .cam_elevation ,
222+ "cam_azimuth" : cfg .training .cam_azimuth ,
223+ },
224+ )
273225 print (f"Saving video to { output_video } with mediapy..." )
274- media .write_video (str (output_video ), frames , fps = int (1.0 / env .cfg .ctrl_dt ))
275226 print ("Done." )
276227 return output_video
277228
0 commit comments