Spaces:
Paused
Paused
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 |
|