Libra-1995 commited on
Commit
b98faf8
·
1 Parent(s): 0676e8e

feat: modify env handler has multi scene

Browse files
Files changed (1) hide show
  1. 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
- def __init__(self, cfg, output):
160
- self.cfg = cfg
161
- self.output = output
162
- self.env = gymnasium.make('hugsim_env/HUGSim-v0', cfg=cfg, output=output)
163
- self._lock = threading.Lock()
 
 
164
  self.reset_env()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
  def close(self):
167
  """
168
  Close the environment and release resources.
169
  """
170
- del self.env
 
 
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._save_data = {'type': 'closeloop', 'frames': []}
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) -> bool:
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._cnt += 1
225
- self._done = terminated or truncated or self._cnt > 400
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._done:
245
- return False
246
 
247
- with open(os.path.join(self.output, 'data.pkl'), 'wb') as wf:
248
  pickle.dump([self._save_data], wf)
249
 
250
- ground_xyz = np.asarray(o3d.io.read_point_cloud(os.path.join(self.output, 'ground.ply')).points)
251
- scene_xyz = np.asarray(o3d.io.read_point_cloud(os.path.join(self.output, 'scene.ply')).points)
252
  results = hugsim_evaluate([self._save_data], ground_xyz, scene_xyz)
253
- with open(os.path.join(self.output, 'eval.json'), 'w') as f:
254
  json.dump(results, f)
255
 
256
- self._log("Evaluation results saved.")
257
- return True
 
 
 
 
 
 
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 _generate_env_handler(self, env_id: str):
 
 
 
 
 
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 = "/app/app_datas/env_output"
292
-
293
- output = os.path.join(cfg.base.output_dir, f"{env_id}_hugsim_env")
 
 
 
 
 
 
294
  os.makedirs(output, exist_ok=True)
295
- return EnvHandler(cfg, output)
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
- return Response(content=pickle.dumps({"done": env_handler.has_done, "state": state}), media_type="application/octet-stream")
 
 
 
 
 
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
- done = env_handler.execute_action(plan_traj)
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.output,
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