一、RL 训练框架

case_generator; data;

train、test、validate.

gym.env;

一边train 一边用当前模型验证validate来获得两条曲线

train curve和validate curve(反映模型优劣的)

二、GA 求解器(solver)框架”

照抄落地的文件结构 + 每个文件该放什么类/函数 + 互相怎么调用。

一、推荐目录结构(最少但够用)
project/
config.json
main_solve.py
main_batch.py
data/
valid/...
test/...
src/
init.py
io/
init.py
case_loader.py
sim/
init.py
decoder.py
model.py
ga/
init.py
chromosome.py
operators.py
solver.py
eval/
init.py
metrics.py
recorder.py

二、每个文件怎么定义(你照着写接口即可)

1)src/io/case_loader.py:只负责“读数据”
职责:把 case_path 读成统一的 Case 对象(你自己的数据结构)。
建议接口:

  • class CaseLoader:

    • load(case_path) -> Case

2)src/sim/model.py:系统与任务的数据结构(纯数据,不做搜索)
职责:定义你问题里的对象:订单、任务、资源(穿梭车、提升机)、距离/时间矩阵等。
建议放:

  • @dataclass Case:包含订单列表、站点、层、巷道、处理时间参数等

  • @dataclass Solution:一个 case 的解(订单序列 + 派车决策)

  • @dataclass SimResult:仿真输出(makespan、各资源时间线等)

3)src/sim/decoder.py:仿真/评估器(你已经写的 decode 就放这里)
职责:给定(Case + Solution)→ 推演 → makespan。
建议接口(最关键):

  • class Decoder:

    • evaluate(case: Case, sol: Solution) -> SimResult 或直接 float

    • (可选)validate(sol, case) -> bool(检查可行性)
      说明:Decoder 不做 GA,不做随机搜索,只做“给你一个解,我算分”。

4)src/ga/chromosome.py:染色体表示(关键:case-specific)
职责:定义个体怎么存,怎么转成 Solution。
建议接口:

  • @dataclass Chromosome:

    • order_perm: list[int] # 订单ID排列(长度=该case订单数)

    • assign_gene: list[int] # 派车/提升机选择(长度同订单或同任务)

    • fitness: float | None

  • def to_solution(ch: Chromosome, case: Case) -> Solution

5)src/ga/operators.py:GA 操作算子(不依赖 decoder)
职责:初始化、选择、交叉、变异、修复。
建议函数:

  • init_population(case, pop_size, rng) -> list[Chromosome]

  • select(pop, k, rng) -> list[Chromosome]

  • crossover(p1, p2, rng) -> (c1, c2) (排序部分用OX/PMX;派车部分用均匀交叉)

  • mutate(ch, rng) -> Chromosome (排序用swap/insert;派车用随机重置)

  • repair(ch, case) -> Chromosome (保证排列合法、派车合法)

6)srcb:GA 主循环(唯一“搜索”所在)
职责:对单个 case 运行 GA,调用 decoder 计算适应度,返回最优解。
建议接口:

  • class GASolver:

    • init(ga_params, rng_seed)

    • solve(case: Case, decoder: Decoder) -> (best_sol: Solution, best_ms: float, curve: list[float])

    • evaluate_population(pop, case, decoder) -> None(写 fitness)
      说明:GASolver 才知道“代数”“收敛曲线”。

7)src/eval/recorder.py:结果记录(Excel/CSV/图)
职责:把每个 case 的结果、曲线保存到文件。
建议接口:

  • class Recorder:

    • log_case_result(case_id, best_ms, run_time, curve)

    • save_summary(path)

    • save_curves(path)
      你如果要保留 pandas 写 xlsx,就放这里。

三、文件之间怎么调用(调用链清晰到一眼可复现)

单个 case 求解(最核心流程)
main_solve.py:

  1. loader = CaseLoader()

  2. case = loader.load(case_path)

  3. decoder = Decoder(sim_params)

  4. ga = GASolver(ga_params, seed)

  5. best_sol, best_ms, curve = ga.solve(case, decoder)

  6. recorder.log_case_result(...)

批量 case(论文实验常用)
main_batch.py:

  1. valid_paths = 列目录得到一批 case_path

  2. for each case_path:

    • load case

    • run GA solve(通常每个 case 重复 R 次不同 seed)

    • 统计 mean/std/min

  3. 输出表格 + 收敛曲线(单case或平均)

四、现在项目里应当删掉/彻底隔离的东西

  • gym、env.step、state、done、PPO_model、torch、visdom(除非只是用 visdom画图,但不建议混着)

  • “train/validate”命名建议改成:

    • solve(求解)

    • evaluate(评估)

    • convergence curve(收敛曲线)

五、现在最容易卡住的点:Solution 的统一定义
染色体两段:订单排序 + 派车选择。建议把 Solution 固定为:

  • order_sequence:订单ID列表(一个排列)

  • assignment:与订单一一对应的资源选择(穿梭车ID、提升机ID,或编码后的策略)
    Decoder 只认 Solution,不直接读 Chromosome。这样后续你换编码方式,Decoder 不用动。

六、一个最小可跑的“主函数骨架”
可以直接按这个写 main_solve.py(不涉及具体业务细节):

from src.io.case_loader import CaseLoader from src.sim.decoder import Decoder from src.ga.solver import GASolver from src.eval.recorder import Recorder def main(): case_path = "./data/test/30_04_01/case_001.json" loader = CaseLoader() case = loader.load(case_path) decoder = Decoder() ga = GASolver(ga_params={"pop": 50, "gen": 200}, rng_seed=0) best_sol, best_ms, curve = ga.solve(case, decoder) rec = Recorder(out_dir="./results") rec.log_case_result(case_id=case.case_id, best_ms=best_ms, run_time=None, curve=curve) rec.save_summary("summary.xlsx") if __name__ == "__main__": main()

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐