This commit is contained in:
Horldsence
2026-09-11 21:00:39 +08:00
parent 2a3ead5d3d
commit 1725cd0891
168 changed files with 170687 additions and 874 deletions
+29
View File
@@ -0,0 +1,29 @@
# project/ 薄兼容层
题目 Prompt 要求 `project/` 目录树;本仓库的真实算法保持唯一一份,
位于 `src/mcm26b`、`scripts/`。本目录只做 re-export/转发,不复制实现。
| Prompt 路径 | 真实实现 |
|---|---|
| `env/simulator_client.py` | `src/mcm26b/protocol/client.py` |
| `env/local_env.py` | `src/mcm26b/hrl/hierarchical_env.py`, `low_level_env.py` |
| `env/particle_filter.py` | `src/mcm26b/particles.py` |
| `policies/high_level_ppo.py` | `src/mcm26b/hrl/policy.py` |
| `policies/low_level_ppo.py` | `src/mcm26b/hrl/policy.py`, `low_level_env.py` |
| `train/curriculum.py` | `src/mcm26b/hrl/curriculum.py` |
| `train/domain_randomization.py` | `src/mcm26b/hrl/curriculum.py` + 配置包装 |
| `eval/evaluate.py` | `scripts/benchmark_hrl.py` |
| `eval/ablation.py` | `scripts/ablate_hrl.py`(P2) |
| `baselines/heuristic.py` | `src/mcm26b/planner/hrl_loop.py` 启发式降级 |
| `baselines/end_to_end_ppo.py` | 显式未实现;单源局部 PPO 不冒充 E2E |
使用示例:
```python
from project.env.local_env import make_local_env
env = make_local_env(problem=3, stage=1, seed=7)
obs, info = env.reset(seed=7)
```
P1 当前交付:`benchmark_hrl.py`、`train_hrl_high.py`、CLI `--strategy hrl`、
`--q4-strategy hrl`。P2 的 BC/Optuna/消融在 smoke 通过后另开。
+4
View File
@@ -0,0 +1,4 @@
"""题目 Prompt 所需目录树的薄兼容层。
真实实现仍位于 ``src/mcm26b``;本包只做 re-export / CLI 转发,避免两份算法逻辑。
"""
+3
View File
@@ -0,0 +1,3 @@
from .heuristic import HeuristicHRL, run_heuristic
__all__ = ["HeuristicHRL", "run_heuristic"]
+16
View File
@@ -0,0 +1,16 @@
"""端到端 PPO 基线占位。
按本轮确认:当前只交付局部 PPO 基线;raw-observation/raw-action 的真正
端到端 PPO 不在 P0+P1 范围内,因此显式标记未实现,避免把单源局部选点
PPO 误称为端到端 baseline。
"""
from __future__ import annotations
def train_end_to_end_ppo(*args, **kwargs):
raise NotImplementedError(
"本轮只交付局部 PPO 基线;真正的端到端 PPO 基线标记为未实现,"
"需单独立项定义原始观测、动作与安全执行边界。")
__all__ = ["train_end_to_end_ppo"]
+16
View File
@@ -0,0 +1,16 @@
"""兼容入口:信息增益/TSP/覆盖规则 + 高层启发式调度。"""
from mcm26b.planner.bayes_loop import BayesLoop
from mcm26b.planner.hrl_loop import HRLLoop
def HeuristicHRL(*args, **kwargs):
"""返回无模型的高层 HRL 闭环(heuristic_action 降级路径)。"""
kwargs.setdefault("high_policy", None)
return HRLLoop(*args, **kwargs)
def run_heuristic(*args, **kwargs):
return HeuristicHRL(*args, **kwargs).run()
__all__ = ["HeuristicHRL", "run_heuristic", "BayesLoop", "HRLLoop"]
+6
View File
@@ -0,0 +1,6 @@
from .simulator_client import SimulatorClient
from .local_env import HierarchicalEnv, LowLevelEnv, HRLReward, make_local_env
from .particle_filter import ChannelParticles
__all__ = ["SimulatorClient", "HierarchicalEnv", "LowLevelEnv", "HRLReward",
"make_local_env", "ChannelParticles"]
+22
View File
@@ -0,0 +1,22 @@
"""兼容入口:本地简化训练环境。
HierarchicalEnv 是高层宏动作环境;LowLevelEnv 是独立八方向导航环境。
本文件不复制实现,只转发 mcm26b.hrl 下的真实类。
"""
from mcm26b.hrl.hierarchical_env import HRLReward, HierarchicalEnv
from mcm26b.hrl.low_level_env import LowLevelEnv
__all__ = ["HierarchicalEnv", "LowLevelEnv", "HRLReward", "make_local_env"]
def make_local_env(*, problem: int = 3, stage: int = 4, seed: int | None = None,
fidelity: str = "production"):
"""按题目 Prompt 的四阶段编号创建训练环境。"""
from mcm26b.hrl.curriculum import STAGES
if not 1 <= int(stage) <= len(STAGES):
raise ValueError(f"stage 必须在 1..{len(STAGES)}")
env = HierarchicalEnv(problem=problem, stage=STAGES[int(stage) - 1],
fidelity=fidelity)
if seed is not None:
env.reset(seed=seed)
return env
+4
View File
@@ -0,0 +1,4 @@
"""兼容入口:逐频道网格粒子/幸存集。"""
from mcm26b.particles import ChannelParticles, angular_gap
__all__ = ["ChannelParticles", "angular_gap"]
+8
View File
@@ -0,0 +1,8 @@
"""兼容入口:真实类见 mcm26b.protocol.client。"""
from mcm26b.protocol.client import (ActionRejected, ClearOutcome, DeadlineExceeded,
ExitInfo, MeasureOutcome, ProtocolError,
ProtocolViolation, SimulatorClient)
__all__ = ["SimulatorClient", "MeasureOutcome", "ClearOutcome", "ExitInfo",
"ProtocolError", "ActionRejected", "ProtocolViolation",
"DeadlineExceeded"]
+4
View File
@@ -0,0 +1,4 @@
from .evaluate import run_benchmark
from .ablation import run_ablation
__all__ = ["run_benchmark", "run_ablation"]
+20
View File
@@ -0,0 +1,20 @@
"""兼容入口:调用 scripts/ablate_hrl.py(P2 后启用)。"""
from __future__ import annotations
import importlib.util
from pathlib import Path
def run_ablation(argv=None) -> int:
path = Path(__file__).resolve().parents[2] / "scripts" / "ablate_hrl.py"
if not path.exists():
raise NotImplementedError(
"scripts/ablate_hrl.py 尚未实现;P1 阶段只保证 benchmark/training/CLI。")
spec = importlib.util.spec_from_file_location("ablate_hrl_compat", path)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return int(module.main(argv))
__all__ = ["run_ablation"]
+17
View File
@@ -0,0 +1,17 @@
"""兼容入口:调用 scripts/benchmark_hrl.py。"""
from __future__ import annotations
import importlib.util
from pathlib import Path
def run_benchmark(argv=None) -> int:
path = Path(__file__).resolve().parents[2] / "scripts" / "benchmark_hrl.py"
spec = importlib.util.spec_from_file_location("benchmark_hrl_compat", path)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return int(module.main(argv))
__all__ = ["run_benchmark"]
+5
View File
@@ -0,0 +1,5 @@
from .high_level_ppo import HighLevelPolicy, load_high_policy
from .low_level_ppo import LowLevelPolicy, load_low_policy
__all__ = ["HighLevelPolicy", "load_high_policy",
"LowLevelPolicy", "load_low_policy"]
+10
View File
@@ -0,0 +1,10 @@
"""兼容入口:高层 MaskablePPO 推理策略。"""
from mcm26b.hrl.policy import HighLevelPolicy
def load_high_policy(model_path: str, *, device: str = "auto",
problem: int | None = None) -> HighLevelPolicy:
return HighLevelPolicy(model_path, device=device, problem=problem)
__all__ = ["HighLevelPolicy", "load_high_policy"]
+9
View File
@@ -0,0 +1,9 @@
"""兼容入口:低层八方向到达策略(离线导航实验)。"""
from mcm26b.hrl.policy import LowLevelPolicy
def load_low_policy(model_path: str, *, device: str = "auto") -> LowLevelPolicy:
return LowLevelPolicy(model_path, device=device)
__all__ = ["LowLevelPolicy", "load_low_policy"]
+5
View File
@@ -0,0 +1,5 @@
from .curriculum import STAGES, Stage, make_scene, training_config
from .domain_randomization import randomize_problem_config
__all__ = ["STAGES", "Stage", "make_scene", "training_config",
"randomize_problem_config"]
+6
View File
@@ -0,0 +1,6 @@
"""兼容入口:课程学习与域随机化。"""
from mcm26b.hrl.curriculum import (STAGES, Stage, make_scene, stage_with_noise,
training_config, training_spec)
__all__ = ["STAGES", "Stage", "make_scene", "stage_with_noise",
"training_config", "training_spec"]
+31
View File
@@ -0,0 +1,31 @@
"""兼容入口:本地域随机化参数包装。
当前真实随机化在 mcm26b.hrl.curriculum.make_scene 内完成;这里只暴露
ProblemConfig 的显式替换助手,便于 Optuna/消融在实验配置中记录随机化范围。
"""
from __future__ import annotations
import dataclasses
from random import Random
from mcm26b.config import ProblemConfig
def randomize_problem_config(base: ProblemConfig, *, seed: int,
bearing_error_half_deg: float | None = None,
r_eff_range: tuple[float, float] | None = None
) -> ProblemConfig:
"""返回带域随机化标量的新配置;不修改全局默认配置。"""
rng = Random(seed)
field = base.field
if bearing_error_half_deg is None:
bearing_error_half_deg = field.bearing_error_half_deg
if r_eff_range is not None:
lo, hi = r_eff_range
if not (0 <= lo <= hi):
raise ValueError("r_eff_range 必须为递增非负区间")
return dataclasses.replace(base, field=dataclasses.replace(
field, bearing_error_half_deg=float(bearing_error_half_deg)))
__all__ = ["randomize_problem_config"]
+20
View File
@@ -0,0 +1,20 @@
"""兼容入口:调用 scripts/tune_hrl.py(P2 后启用)。"""
from __future__ import annotations
import importlib.util
from pathlib import Path
def run_tuning(argv=None) -> int:
path = Path(__file__).resolve().parents[2] / "scripts" / "tune_hrl.py"
if not path.exists():
raise NotImplementedError(
"scripts/tune_hrl.py 尚未实现;P1 阶段先冻结超参并留待 P2。")
spec = importlib.util.spec_from_file_location("tune_hrl_compat", path)
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return int(module.main(argv))
__all__ = ["run_tuning"]