Spaces:
Starting
on
T4
Starting
on
T4
Commit
·
b98faf8
1
Parent(s):
0676e8e
feat: modify env handler has multi scene
Browse files- web_server.py +102 -34
web_server.py
CHANGED
@@ -9,12 +9,13 @@ import hugsim_env
|
|
9 |
import subprocess as sp
|
10 |
from collections import deque, OrderedDict
|
11 |
from datetime import datetime
|
12 |
-
from typing import Any, Dict, Optional
|
|
|
13 |
sys.path.append(os.getcwd())
|
14 |
|
15 |
from fastapi import FastAPI, Body, Header, Depends, HTTPException, Query
|
16 |
from fastapi.responses import HTMLResponse, Response
|
17 |
-
from omegaconf import OmegaConf
|
18 |
from huggingface_hub import HfApi
|
19 |
import open3d as o3d
|
20 |
import numpy as np
|
@@ -155,29 +156,65 @@ class FifoDict:
|
|
155 |
return self._order_dict.get(key, None)
|
156 |
|
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
class EnvHandler:
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
self.
|
|
|
|
|
164 |
self.reset_env()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
|
166 |
def close(self):
|
167 |
"""
|
168 |
Close the environment and release resources.
|
169 |
"""
|
170 |
-
|
|
|
|
|
171 |
self._log("Environment closed.")
|
172 |
|
173 |
def reset_env(self):
|
174 |
"""
|
175 |
Reset the environment and initialize variables.
|
176 |
"""
|
177 |
-
self._cnt = 0
|
178 |
self._done = False
|
179 |
-
self.
|
180 |
-
self._obs, self._info = self.env.reset()
|
181 |
self._log_list = deque(maxlen=100)
|
182 |
self._log("Environment reset complete.")
|
183 |
|
@@ -198,6 +235,15 @@ class EnvHandler:
|
|
198 |
bool: True if the episode is done, False otherwise.
|
199 |
"""
|
200 |
return self._done
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
201 |
|
202 |
@property
|
203 |
def log_list(self) -> deque:
|
@@ -208,7 +254,7 @@ class EnvHandler:
|
|
208 |
"""
|
209 |
return self._log_list
|
210 |
|
211 |
-
def execute_action(self, plan_traj: np.ndarray) ->
|
212 |
"""
|
213 |
Execute the action based on the planned trajectory.
|
214 |
Args:
|
@@ -221,8 +267,8 @@ class EnvHandler:
|
|
221 |
self._log("Executing action:", action)
|
222 |
|
223 |
self._obs, _, terminated, truncated, self._info = self.env.step(action)
|
224 |
-
self.
|
225 |
-
self.
|
226 |
|
227 |
imu_plan_traj = plan_traj[:, [1, 0]]
|
228 |
imu_plan_traj[:, 1] *= -1
|
@@ -241,20 +287,26 @@ class EnvHandler:
|
|
241 |
'rc': self._info['rc']
|
242 |
})
|
243 |
|
244 |
-
if not self.
|
245 |
-
return False
|
246 |
|
247 |
-
with open(os.path.join(self.
|
248 |
pickle.dump([self._save_data], wf)
|
249 |
|
250 |
-
ground_xyz = np.asarray(o3d.io.read_point_cloud(os.path.join(self.
|
251 |
-
scene_xyz = np.asarray(o3d.io.read_point_cloud(os.path.join(self.
|
252 |
results = hugsim_evaluate([self._save_data], ground_xyz, scene_xyz)
|
253 |
-
with open(os.path.join(self.
|
254 |
json.dump(results, f)
|
255 |
|
256 |
-
self._log("Evaluation results saved.")
|
257 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
258 |
|
259 |
def _log(self, *messages):
|
260 |
log_message = f"[{str(datetime.now())}]" + " ".join([str(msg) for msg in messages]) + "\n"
|
@@ -267,7 +319,12 @@ class EnvHandlerManager:
|
|
267 |
self._env_handlers = {}
|
268 |
self._lock = threading.Lock()
|
269 |
|
270 |
-
def
|
|
|
|
|
|
|
|
|
|
|
271 |
base_path = os.path.join(os.path.dirname(__file__), 'docker', "web_server_config", 'nuscenes_base.yaml')
|
272 |
scenario_path = os.path.join(os.path.dirname(__file__), 'docker', "web_server_config", 'scene-0383-medium-00.yaml')
|
273 |
camera_path = os.path.join(os.path.dirname(__file__), 'docker', "web_server_config", 'nuscenes_camera.yaml')
|
@@ -288,11 +345,17 @@ class EnvHandlerManager:
|
|
288 |
model_config = OmegaConf.load(os.path.join(model_path, 'cfg.yaml'))
|
289 |
model_config.update({"model_path": "/app/app_datas/PAMI2024/release/ss/scenes/nuscenes/scene-0383"})
|
290 |
cfg.update(model_config)
|
291 |
-
cfg.base.output_dir =
|
292 |
-
|
293 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
294 |
os.makedirs(output, exist_ok=True)
|
295 |
-
return EnvHandler(
|
296 |
|
297 |
def exists_env_handler(self, env_id: str) -> bool:
|
298 |
"""
|
@@ -383,7 +446,12 @@ def get_current_state_endpoint(env_handler: EnvHandler = Depends(_get_env_handle
|
|
383 |
Get the current state of the environment.
|
384 |
"""
|
385 |
state = env_handler.get_current_state()
|
386 |
-
|
|
|
|
|
|
|
|
|
|
|
387 |
|
388 |
|
389 |
@app.post("/execute_action")
|
@@ -407,29 +475,29 @@ def execute_action_endpoint(
|
|
407 |
return Response(content=cache_result, media_type="application/octet-stream")
|
408 |
|
409 |
if env_handler.has_done:
|
410 |
-
result = pickle.dumps({"done": True, "state": env_handler.get_current_state()})
|
411 |
_result_dict.push(transaction_id, result)
|
412 |
return Response(content=result, media_type="application/octet-stream")
|
413 |
|
414 |
plan_traj = _load_numpy_ndarray_json_str(plan_traj)
|
415 |
-
|
416 |
-
if done:
|
417 |
token_info = get_token_info(auth_token)
|
418 |
env_manager.close_env_handler(token_info["submission_id"])
|
419 |
delete_client_space(token_info["client_space_id"])
|
420 |
update_submission_status(token_info["team_id"], token_info["submission_id"], SubmissionStatus.SUCCESS.value)
|
421 |
hf_api.upload_folder(
|
422 |
repo_id=COMPETITION_ID,
|
423 |
-
folder_path=env_handler.
|
424 |
repo_type="dataset",
|
425 |
path_in_repo=f"eval_results/{token_info['submission_id']}",
|
426 |
)
|
427 |
-
result = pickle.dumps({"done": done, "state": env_handler.get_current_state()})
|
428 |
_result_dict.push(transaction_id, result)
|
429 |
return Response(content=result, media_type="application/octet-stream")
|
430 |
|
431 |
state = env_handler.get_current_state()
|
432 |
-
result = pickle.dumps({"done": done, "state": state})
|
433 |
_result_dict.push(transaction_id, result)
|
434 |
return Response(content=result, media_type="application/octet-stream")
|
435 |
|
|
|
9 |
import subprocess as sp
|
10 |
from collections import deque, OrderedDict
|
11 |
from datetime import datetime
|
12 |
+
from typing import Any, Dict, Optional, List
|
13 |
+
from dataclasses import dataclass
|
14 |
sys.path.append(os.getcwd())
|
15 |
|
16 |
from fastapi import FastAPI, Body, Header, Depends, HTTPException, Query
|
17 |
from fastapi.responses import HTMLResponse, Response
|
18 |
+
from omegaconf import OmegaConf, DictConfig
|
19 |
from huggingface_hub import HfApi
|
20 |
import open3d as o3d
|
21 |
import numpy as np
|
|
|
156 |
return self._order_dict.get(key, None)
|
157 |
|
158 |
|
159 |
+
@dataclass
|
160 |
+
class SceneConfig:
|
161 |
+
name: str
|
162 |
+
cfg: DictConfig
|
163 |
+
|
164 |
+
|
165 |
+
@dataclass
|
166 |
+
class EnvExecuteResult:
|
167 |
+
cur_scene_done: bool
|
168 |
+
done: bool
|
169 |
+
|
170 |
+
|
171 |
class EnvHandler:
|
172 |
+
"""A class to handle the environment for HUGSim.
|
173 |
+
This can include multiple scene and configurations.
|
174 |
+
"""
|
175 |
+
def __init__(self, scene_list: List[SceneConfig], base_output: str):
|
176 |
+
self.scene_list = scene_list
|
177 |
+
self.base_output = base_output
|
178 |
+
self.env = None
|
179 |
self.reset_env()
|
180 |
+
self._lock = threading.Lock()
|
181 |
+
|
182 |
+
def _switch_scene(self, scene_index: int):
|
183 |
+
"""
|
184 |
+
Switch to a different scene based on the index.
|
185 |
+
Args:
|
186 |
+
scene_index (int): The index of the scene to switch to.
|
187 |
+
"""
|
188 |
+
if scene_index < 0 or scene_index >= len(self.scene_list):
|
189 |
+
raise ValueError("Invalid scene index.")
|
190 |
+
|
191 |
+
self.cur_scene_index = scene_index
|
192 |
+
scene_config = self.scene_list[scene_index]
|
193 |
+
self.env.close()
|
194 |
+
self.cur_otuput = os.path.join(self.base_output, scene_config.name)
|
195 |
+
self.env = gymnasium.make('hugsim_env/HUGSim-v0', cfg=scene_config.cfg, output=self.cur_otuput)
|
196 |
+
self._scene_cnt = 0
|
197 |
+
self._scene_done = False
|
198 |
+
self._save_data = {'type': 'closeloop', 'frames': []}
|
199 |
+
self._obs, self._info = self.env.reset()
|
200 |
+
|
201 |
+
self._log(f"Switched to scene: {scene_config.name}")
|
202 |
|
203 |
def close(self):
|
204 |
"""
|
205 |
Close the environment and release resources.
|
206 |
"""
|
207 |
+
if self.env is not None:
|
208 |
+
del self.env
|
209 |
+
self.env = None
|
210 |
self._log("Environment closed.")
|
211 |
|
212 |
def reset_env(self):
|
213 |
"""
|
214 |
Reset the environment and initialize variables.
|
215 |
"""
|
|
|
216 |
self._done = False
|
217 |
+
self._switch_scene(0)
|
|
|
218 |
self._log_list = deque(maxlen=100)
|
219 |
self._log("Environment reset complete.")
|
220 |
|
|
|
235 |
bool: True if the episode is done, False otherwise.
|
236 |
"""
|
237 |
return self._done
|
238 |
+
|
239 |
+
@property
|
240 |
+
def has_scene_done(self) -> bool:
|
241 |
+
"""
|
242 |
+
Check if the current scene is done.
|
243 |
+
Returns:
|
244 |
+
bool: True if the current scene is done, False otherwise.
|
245 |
+
"""
|
246 |
+
return self._scene_done
|
247 |
|
248 |
@property
|
249 |
def log_list(self) -> deque:
|
|
|
254 |
"""
|
255 |
return self._log_list
|
256 |
|
257 |
+
def execute_action(self, plan_traj: np.ndarray) -> EnvExecuteResult:
|
258 |
"""
|
259 |
Execute the action based on the planned trajectory.
|
260 |
Args:
|
|
|
267 |
self._log("Executing action:", action)
|
268 |
|
269 |
self._obs, _, terminated, truncated, self._info = self.env.step(action)
|
270 |
+
self._scene_cnt += 1
|
271 |
+
self._scene_done = terminated or truncated or self._scene_cnt > 400
|
272 |
|
273 |
imu_plan_traj = plan_traj[:, [1, 0]]
|
274 |
imu_plan_traj[:, 1] *= -1
|
|
|
287 |
'rc': self._info['rc']
|
288 |
})
|
289 |
|
290 |
+
if not self._scene_done:
|
291 |
+
return EnvExecuteResult(cur_scene_done=False, done=False)
|
292 |
|
293 |
+
with open(os.path.join(self.cur_otuput, 'data.pkl'), 'wb') as wf:
|
294 |
pickle.dump([self._save_data], wf)
|
295 |
|
296 |
+
ground_xyz = np.asarray(o3d.io.read_point_cloud(os.path.join(self.cur_otuput, 'ground.ply')).points)
|
297 |
+
scene_xyz = np.asarray(o3d.io.read_point_cloud(os.path.join(self.cur_otuput, 'scene.ply')).points)
|
298 |
results = hugsim_evaluate([self._save_data], ground_xyz, scene_xyz)
|
299 |
+
with open(os.path.join(self.cur_otuput, 'eval.json'), 'w') as f:
|
300 |
json.dump(results, f)
|
301 |
|
302 |
+
self._log(f"Scene {self.cur_scene_index} completed. Evaluation results saved.")
|
303 |
+
|
304 |
+
if self.cur_scene_index < len(self.scene_list) - 1:
|
305 |
+
self._switch_scene(self.cur_scene_index + 1)
|
306 |
+
return EnvExecuteResult(cur_scene_done=True, done=False)
|
307 |
+
|
308 |
+
self._done = True
|
309 |
+
return EnvExecuteResult(cur_scene_done=True, done=True)
|
310 |
|
311 |
def _log(self, *messages):
|
312 |
log_message = f"[{str(datetime.now())}]" + " ".join([str(msg) for msg in messages]) + "\n"
|
|
|
319 |
self._env_handlers = {}
|
320 |
self._lock = threading.Lock()
|
321 |
|
322 |
+
def _get_scene_list(self, env_id: str, base_output: str) -> List[SceneConfig]:
|
323 |
+
"""
|
324 |
+
Load the scene configurations from the YAML files.
|
325 |
+
Returns:
|
326 |
+
List[SceneConfig]: A list of scene configurations.
|
327 |
+
"""
|
328 |
base_path = os.path.join(os.path.dirname(__file__), 'docker', "web_server_config", 'nuscenes_base.yaml')
|
329 |
scenario_path = os.path.join(os.path.dirname(__file__), 'docker', "web_server_config", 'scene-0383-medium-00.yaml')
|
330 |
camera_path = os.path.join(os.path.dirname(__file__), 'docker', "web_server_config", 'nuscenes_camera.yaml')
|
|
|
345 |
model_config = OmegaConf.load(os.path.join(model_path, 'cfg.yaml'))
|
346 |
model_config.update({"model_path": "/app/app_datas/PAMI2024/release/ss/scenes/nuscenes/scene-0383"})
|
347 |
cfg.update(model_config)
|
348 |
+
cfg.base.output_dir = base_output
|
349 |
+
return [
|
350 |
+
SceneConfig(name=cfg.scenario.scene_name, cfg=cfg)
|
351 |
+
]
|
352 |
+
|
353 |
+
def _generate_env_handler(self, env_id: str):
|
354 |
+
base_output = "/app/app_datas/env_output"
|
355 |
+
scene_list = self._get_scene_list(env_id, base_output)
|
356 |
+
output = os.path.join(base_output, f"{env_id}_hugsim_env")
|
357 |
os.makedirs(output, exist_ok=True)
|
358 |
+
return EnvHandler(scene_list, base_output=output)
|
359 |
|
360 |
def exists_env_handler(self, env_id: str) -> bool:
|
361 |
"""
|
|
|
446 |
Get the current state of the environment.
|
447 |
"""
|
448 |
state = env_handler.get_current_state()
|
449 |
+
data = {
|
450 |
+
"done": env_handler.has_done,
|
451 |
+
"cur_scene_done": env_handler.has_scene_done,
|
452 |
+
"state": state,
|
453 |
+
}
|
454 |
+
return Response(content=pickle.dumps(data), media_type="application/octet-stream")
|
455 |
|
456 |
|
457 |
@app.post("/execute_action")
|
|
|
475 |
return Response(content=cache_result, media_type="application/octet-stream")
|
476 |
|
477 |
if env_handler.has_done:
|
478 |
+
result = pickle.dumps({"done": True, "cur_scene_done": True, "state": env_handler.get_current_state()})
|
479 |
_result_dict.push(transaction_id, result)
|
480 |
return Response(content=result, media_type="application/octet-stream")
|
481 |
|
482 |
plan_traj = _load_numpy_ndarray_json_str(plan_traj)
|
483 |
+
execute_result = env_handler.execute_action(plan_traj)
|
484 |
+
if execute_result.done:
|
485 |
token_info = get_token_info(auth_token)
|
486 |
env_manager.close_env_handler(token_info["submission_id"])
|
487 |
delete_client_space(token_info["client_space_id"])
|
488 |
update_submission_status(token_info["team_id"], token_info["submission_id"], SubmissionStatus.SUCCESS.value)
|
489 |
hf_api.upload_folder(
|
490 |
repo_id=COMPETITION_ID,
|
491 |
+
folder_path=env_handler.base_output,
|
492 |
repo_type="dataset",
|
493 |
path_in_repo=f"eval_results/{token_info['submission_id']}",
|
494 |
)
|
495 |
+
result = pickle.dumps({"done": execute_result.done, "cur_scene_done": execute_result.cur_scene_done, "state": env_handler.get_current_state()})
|
496 |
_result_dict.push(transaction_id, result)
|
497 |
return Response(content=result, media_type="application/octet-stream")
|
498 |
|
499 |
state = env_handler.get_current_state()
|
500 |
+
result = pickle.dumps({"done": execute_result.done, "cur_scene_done": execute_result.cur_scene_done, "state": state})
|
501 |
_result_dict.push(transaction_id, result)
|
502 |
return Response(content=result, media_type="application/octet-stream")
|
503 |
|