diff --git a/UPDATE.md b/UPDATE.md index c956e71..e8da134 100644 --- a/UPDATE.md +++ b/UPDATE.md @@ -1,4 +1,7 @@ # UPDATE +## 20260101 +### v1.0.3 +Fix bug: 修复多进程中修改全局参数配置的问题, 同一个进程池中修改的全局变量会被保留, 因此task_register中需要实例化对象 ## 20251231 ### v1.0.2 1. 删除pyproject.toml文件, 使用`pip install -e .`就可以安装到pip easy-install.pth中, vscode能找到robogauge包 diff --git a/robogauge/tasks/pipeline/base_pipeline.py b/robogauge/tasks/pipeline/base_pipeline.py index 848f129..1f44960 100644 --- a/robogauge/tasks/pipeline/base_pipeline.py +++ b/robogauge/tasks/pipeline/base_pipeline.py @@ -28,12 +28,14 @@ class BasePipeline: run_name: str, simulator_cfg: MujocoConfig, robot_cfg: RobotConfig, - gauge_cfg: BaseGaugeConfig + gauge_cfg: BaseGaugeConfig, + args, ): self.run_name = run_name self.sim_cfg = simulator_cfg self.robot_cfg = robot_cfg self.gauge_cfg = gauge_cfg + self.args = args self.sim: MujocoSimulator = eval(simulator_cfg.simulator_class)(simulator_cfg) self.robot: BaseRobot = eval(robot_cfg.robot_class)(robot_cfg) @@ -44,7 +46,7 @@ class BasePipeline: # save configs cfg = {} - for name in ['sim_cfg', 'robot_cfg', 'gauge_cfg']: + for name in ['args', 'sim_cfg', 'robot_cfg', 'gauge_cfg']: obj = getattr(self, name) obj_dict = class_to_dict(obj) cfg.update({name: obj_dict}) diff --git a/robogauge/tasks/pipeline/stress_pipeline.py b/robogauge/tasks/pipeline/stress_pipeline.py index 87cb802..b200fcb 100644 --- a/robogauge/tasks/pipeline/stress_pipeline.py +++ b/robogauge/tasks/pipeline/stress_pipeline.py @@ -38,54 +38,66 @@ GOALS = { } def run_pipeline(args, progress_queue, data): - args = deepcopy(args) - task_id = data['task_id'] - search = data['search_max_level'] - task_label = f"[{data['terrain_name']}] M:{data['base_mass']} F:{data['friction']}" - progress_data = ProgressData( - task_id=task_id, - msg_prefix=task_label + ' ', - progress_queue=progress_queue - ) + try: + args = deepcopy(args) + task_id = data['task_id'] + search = data['search_max_level'] + task_label = f"[{data['terrain_name']}] M:{data['base_mass']} F:{data['friction']}" + progress_data = ProgressData( + task_id=task_id, + msg_prefix=task_label + ' ', + progress_queue=progress_queue + ) - args.friction = data['friction'] - args.frictions = [data['friction']] - args.base_mass = data['base_mass'] - args.base_masses = [data['base_mass']] - args.task_name = f"{data['task_robot_model']}.{data['terrain_name']}" - args.experiment_name = f"{args.experiment_name}_{data['terrain_name']}_M{data['base_mass']}_F{data['friction']}" - - if search is True: - args.goals = GOALS['level_pipeline'] - args.spawn_type = "level_search" - level, level_results = LevelPipeline(args, console_output=False, progress_data=progress_data).run() - if level == 0: # no valid level found - report_progress(progress_data, ProgressTypes.FINISH, desc=f"❌ Failed (Lv 0)") - results = { - 'success': False, - 'results': level_results, - 'data': data, - 'level': 0, - } - return results - report_progress(progress_data, ProgressTypes.RESET, total=0, desc=f"✅ Found Lv {level} -> Running") - progress_data.msg_prefix += f"(Lv {level}) " - else: - level = None # flat terrain + args.friction = data['friction'] + args.frictions = [data['friction']] + args.base_mass = data['base_mass'] + args.base_masses = [data['base_mass']] args.task_name = f"{data['task_robot_model']}.{data['terrain_name']}" - args.experiment_name = f"{args.experiment_name}_{data['terrain_name']}" - - args.level = level - args.goals = GOALS['multi_pipeline'] - args.spawn_type = "level_eval" - results = { - 'success': True, - 'results': MultiPipeline(args, console_output=False, progress_data=progress_data).run(), - 'data': data, - 'level': level, - } - report_progress(progress_data, ProgressTypes.FINISH, desc=f"✅ Done (Lv {level})") - return results + args.experiment_name = f"{args.experiment_name}_{data['terrain_name']}_M{data['base_mass']}_F{data['friction']}" + + if search is True: + args.goals = GOALS['level_pipeline'] + args.spawn_type = "level_search" + level, level_results = LevelPipeline(args, console_output=False, progress_data=progress_data).run() + if level == 0: # no valid level found + report_progress(progress_data, ProgressTypes.FINISH, desc=f"❌ Failed (Lv 0)") + results = { + 'success': False, + 'results': level_results, + 'data': data, + 'level': 0, + } + return results + report_progress(progress_data, ProgressTypes.RESET, total=0, desc=f"✅ Found Lv {level} -> Running") + progress_data.msg_prefix += f"(Lv {level}) " + else: + level = None # flat terrain + args.task_name = f"{data['task_robot_model']}.{data['terrain_name']}" + args.experiment_name = f"{args.experiment_name}_{data['terrain_name']}" + + args.level = level + args.goals = GOALS['multi_pipeline'] + args.spawn_type = "level_eval" + results = { + 'success': True, + 'results': MultiPipeline(args, console_output=False, progress_data=progress_data).run(), + 'data': data, + 'level': level, + } + report_progress(progress_data, ProgressTypes.FINISH, desc=f"✅ Done (Lv {level})") + return results + except Exception as e: + error_context = ( + f"\n{'='*20} 💥 CRASH CONTEXT 💥 {'='*20}\n" + f"Terrain : {data.get('terrain_name')}\n" + f"Friction : {data.get('friction')}\n" + f"Base Mass : {data.get('base_mass')}\n" + f"Task ID : {data.get('task_id')}\n" + f"Original Error: {str(e)}\n" + f"{'='*60}" + ) + raise RuntimeError(error_context) from e class StressPipeline: def __init__(self, args): diff --git a/robogauge/utils/task_register.py b/robogauge/utils/task_register.py index c012570..42aae70 100644 --- a/robogauge/utils/task_register.py +++ b/robogauge/utils/task_register.py @@ -33,9 +33,9 @@ class TaskRegister(): def get_cfgs(self, name): if name not in self.sim_cfgs: raise ValueError(f"Task '{name}' is not registered, checkout '{ROBOGAUGE_ROOT_DIR}/robogauge/tasks/__init__.py'.") - sim_cfg = self.sim_cfgs[name] - gauger_cfg = self.gauger_cfgs[name] - robot_cfg = self.robot_cfgs[name] + sim_cfg = self.sim_cfgs[name]() + gauger_cfg = self.gauger_cfgs[name]() + robot_cfg = self.robot_cfgs[name]() return sim_cfg, gauger_cfg, robot_cfg def make_pipeline(self, args=None, sim_cfg=None, gauger_cfg=None, robot_cfg=None, create_logger=True): @@ -55,7 +55,7 @@ class TaskRegister(): run_name = args.run_name + f'_{args.seed}' if create_logger: logger.create(args.experiment_name, run_name) - return pipeline_class(run_name, sim_cfg, robot_cfg, gauger_cfg) + return pipeline_class(run_name, sim_cfg, robot_cfg, gauger_cfg, args) def update_args_to_cfg(self, sim_cfg, gauger_cfg, robot_cfg, args): if args.model_path is not None: