首页 / 资讯中心 / 文章详情

强化学习在车间调度中的应用:DQN与PPO实战对比与经验总结

强化学习在车间调度中的应用:DQN与PPO实战对比与经验总结 ★ FEATURED ARTICLE
做车间调度有几年大部分时间都在和遗传算法、模拟退火较劲后来真正让我想换方向的是作业车间Job Shop里那种工序交错、设备共用的复杂度——也就是那时候我开始试强化学习把 DQN 和 PPO 分别塞进调度决策里。前期踩了不少坑也摸出了一些门道。这篇文章不打算写成论文综述而是按我实际动手的经历把环境建模、动作空间设计、奖励函数、两个算法的训练细节和对比结果完整梳理一遍希望能给同样想往“强化学习调度”方向走的人节省一点试错时间。不管你是刚接触强化学习、想找个工业场景练手还是已经在用传统调度算法、想换条路试试这篇内容应该都能给你一些可落地的参考。1. 车间调度问题的本质与强化学习的切入点1.1 一个被低估的离散优化难题作业车间调度Job Shop Scheduling简称 JSP说起来一句话就能讲明白给定一批工件每个工件由若干道工序组成各工序必须在指定设备上按固定顺序加工问怎么安排每台设备上工序的开始时间使整体完工时间最短。但这句话背后是一个 NP-hard 问题。规模稍微上来一点——比如 15 个工件、10 台设备、每个工件 5 道工序——决定变量和约束的数量就非常可观穷举想都别想。我最早接触这个问题是在一个模拟项目 X 里一条移动部件车间设备 8 台订单每天波动临时插单和设备故障时有发生。当时组里用整数规划求解器跑静态排产最优解要跑一晚上才能出来第二天早上生产计划早该下发了。后来换启发式规则最短工时优先、最早交期优先之类的组合响应快了但质量忽高忽低。那段时间我意识到一件事车间调度不仅仅是要找到一个“最优解”更重要的是在有限时间内、面对动态扰动时给出一个“足够好且能执行”的解。1.2 传统方法的三个天花板传统方法大体分三类各有各的难受数学规划MILP、约束规划这类方法在小规模样例上可以证最优但计算复杂度随规模指数级上升。工程上超过十几台设备、几十个工件求解时间就完全不可控更不用说随时可能出现的插单。调度规则SPT、EDD、LPT 这些规则实现简单、速度快但它是贪婪且近视的只会根据当前局部状态做决策不会考虑未来几道工序的连锁影响。单一规则很难在完工时间、设备利用率、准时交付等多个目标之间取得平衡。元启发式遗传算法、模拟退火、禁忌搜索等效果确实比规则好但本质是离线批处理——给你一整张订单表它迭代若干代后给一版方案。调度环境一变设备故障、新单插入整张表又要重新算在线响应能力基本为零。这些方法的共同问题是把调度当成一次性求解任务而不是序列决策过程。可实际车间里调度员每天都在做决策——这台设备空闲了接下来加工哪个工件这个订单要插单先插谁本质上是一个“边看边做”的过程。1.3 强化学习换了一种打法强化学习的核心思想恰恰就是“边看边做”智能体在每个决策点观察当前生产状态选择动作比如从可选工序里挑一个环境反馈奖励比如时间越短奖励越高智能体通过反复试错改进策略。这和人类调度员的日常工作逻辑高度一致。于是问题就清晰了调度问题可以建模成马尔可夫决策过程MDP然后用强化学习算法求解策略。算法选型上业界最常拿来对比的两条路线就是 DQN 和 PPO。DQN 是值函数类方法的代表适合离散动作空间训练稳定在小规模调度场景里很友好PPO 是策略梯度类方法的代表通过 Actor-Critic 结构直接学习策略分布在复杂动作空间和大规模场景下扩展性更好。一个重要的认知转变传统优化在找“最优计划”强化学习在找“最优决策规则”。前者输出一张排产表后者输出一个可以实时决策的调度策略。这个区别决定了后续所有建模方式的选择。2. 建模把车间调度翻译成强化学习的语言2.1 MDP 五元组的调度化改造任何强化学习问题都要先定义五个东西状态、动作、状态转移、奖励、折扣因子。车间调度场景下我的做法是状态当前时刻所有设备的忙闲情况、各工件已完成的工序数和剩余加工时间、设备队列长度、当前时间点等。动作在某个决策点比如有设备空闲从所有“当前可以开工”的工序集合中选一个安排到对应设备上。状态转移执行动作后时间推进到下一个事件发生时刻某道工序完成或某台设备空闲状态自然更新。奖励单步时间惩罚 完工时的完工时间惩罚后面细讲。折扣因子通常取 0.95~0.99让智能体既关注当下又放眼全局。这套建模方式里最关键的假设是“事件驱动”而不是“时间步驱动”。如果你把每个固定时间单位都当成决策点状态里的大部分信息都不会变化训练效率极低事件驱动则只在真正需要决策的时刻机器空闲、有新工序释放才触发智能体跟实际调度的节拍完全一致。2.2 状态设计别把整个排产表塞给网络刚开始做状态设计时我犯过一个典型错误想把整个甘特图信息直接塞给神经网络。结果输入维度爆炸训练慢得不忍直视效果并没有变好。后来总结下来状态特征尽量用“归一化的标量向量”只保留决策真正需要的信息每个工件的已完成工序比例、剩余总加工时间占初始总工时的比例每台设备的当前任务剩余加工时间空闲则为 0、设备累计负载率当前时刻所有可执行工序的最小剩余加工时间、平均剩余加工时间订单交期紧迫度剩余可用时间 ÷ 剩余加工时间越小越紧急。把这些做成 30~80 维的特征向量对 DQN 的 MLP 输入层来说非常友好。状态里千万不要放冗余的绝对时间戳和工件编号这类和决策无关的信息归一化更是必须的不同量纲的特征直接喂给网络梯度根本没法收敛。经验心得调度状态设计的核心是“决策相关性”。问自己一个问题如果把这个特征删掉一个资深调度员还能不能做决定如果不能那它就是核心特征。2.3 动作设计单步决策还是块决策动作空间是调度场景里最容易被搞错的地方。我的推荐方案是“候选工序集合索引”在每个决策点系统能实际开工的工序是有限的受前置工序和工装就绪状态约束动作空间大小 当前可选工序集合大小。好处很明显动作空间动态变化但始终不大DQN 和 PPO 都能处理坏处是实现时要处理“动作掩码”问题——不同状态下可选动作集合不同网络输出层没法固定维度。解决方式有两种。第一种是把动作空间固定为所有工序的总数量每次只对可选工序位置保留有效 Q 值或概率把非可选动作的 Q 值设为负无穷或概率设为 0。第二种是用“排序式动作”网络输出对候选工序的优先级分数每次选择得分最高的工序动作维度恒定为候选工序数逻辑上也更接近调度员的“人工优先级”思维。个人更推荐第二种因为它的动作含义可解释后续还可以兼容连续动作扩展比如输出调度规则的权重而第一种在工序数量大的时候输出层会非常笨重。2.4 奖励设计稀疏奖励会把人坑死奖励函数是强化学习调度里最玄学也最关键的部分。最开始我用的纯稀疏奖励每个 episode 结束后如果完工时间比某个基线短给 1否则给 -1。结果训练一万多轮策略基本没进步——中间过程完全没有梯度信号智能体根本不知道自己哪一步做得对。后来改成混合奖励效果立竿见影单步奖励每推进一步完成一道工序给一个小的负奖励数值等于本次工序加工时间取负。这样智能体会天然偏好短工序但会被“只选短工序、导致后续瓶颈”的局部最优骗到。增量奖励每完成一道工序计算当前“已排工序最大完工时间”相比上一步的变化量奖励 改进量 × 系数。这让智能体能感受到每一步对整个计划进度的贡献。回合结束奖励最终 makespan 与基线比如最短工时优先规则的结果的差值负反馈或正反馈。混合奖励下智能体既能从单步中获得密集信号又不会丢失全局目标。后面我还会专门说奖励被“钻空子”的坑。3. DQN 在车间调度中的应用实战3.1 DQN 的底层逻辑和适用边界DQN 的基本逻辑不复杂它用深度神经网络逼近 Q 函数 Q(s,a)也就是“在状态 s 下选择动作 a之后一直按最优策略走能拿到的期望累计回报”。训练时通过贝尔曼方程做自举更新当前 Q 值的估计 即时奖励 折扣 × 下一状态的最大 Q 值估计。这套机制的适配特征很明确离散动作空间、动作数量不大、环境模型可以反复离线采样。车间调度在决策点上的候选工序通常就那么几个到几十个完全在 DQN 舒适区内。但要注意如果候选工序持续超过百级DQN 输出层的 Q 值近似误差会显著增大训练稳定性明显变差这时候就该考虑 PPO 那条路了。3.2 网络结构与输入输出设计我的 DQN 网络结构很朴素输入层接归一化状态向量经过两层 128 或 256 神经元的全连接层加 ReLU 激活输出层维度等于工件数量而非工序总数每个输出对应“下一个决策点优先选择哪个工件”。实际选择时再结合动作掩码过滤掉当前不可开工的工件。这里有个细节为啥输出层按工件维度而不是工序维度因为同一个工件的工序必须按顺序加工只要决策了“下一个上哪个工件”具体工序就是这个工件的下一道不需要再额外区分。这让动作空间天然小了很多训练也更快。如果想让网络有更强区分度可以加一个 Dueling 结构把 Q 值拆成状态价值 V(s) 和动作优势 A(s,a)。调度问题里大部分状态的好坏比如快下班了 vs 刚接班与具体动作关系不大拆开之后网络学习效率明显提升。我实测下来Dueling DQN 比普通 DQN 收敛快 30% 左右。3.3 训练流程与关键超参数下面这段是核心训练流程的伪代码示意# 训练主循环伪代码 初始化 Q 主网络和 Q 目标网络target_net 初始化经验回放缓冲区 replay_buffer for episode in range(total_episodes): 重置调度环境生成一张新的订单任务列表 状态 环境初始化特征 while not 环境终止: # 根据 epsilon 贪心策略选择动作在可选工序集合上 action epsilon_greedy(state, available_ops, epsilon) 执行动作推进仿真得到 reward, next_state, done 将 (state, action, reward, next_state, mask) 存入 replay_buffer if len(replay_buffer) batch_size: 采样一个批次的经验 计算 TD 目标 reward discount * max(Q_target(next_state), masked) 对 Q 主网络做一次梯度下降 每隔 C 步将主网络参数同步到目标网络 state next_state epsilon 按衰减调度表降低关键超参数我列一下基于常见实践的补充具体值要按场景微调超参数推荐范围说明学习率1e-3 ~ 3e-4过大导致震荡过小收敛慢回放缓冲区大小5万~50万条调度状态多样缓冲区不能太小批次大小64~256128 是性价比最高的点目标网络更新频率1000~5000 步更新太频繁会放大估计误差epsilon 初始值1.0~0.5前期多探索后期多利用epsilon 衰减策略指数衰减到 0.05不要衰减到 0保留少量随机性折扣因子0.95~0.99越大越考虑远期影响3.4 DQN 调度实战里躲不开的那些坑第一个坑是动作掩码实现失误。RL 框架里非法动作如果没被屏蔽网络会学出“明知道某道工序还没释放却仍然选它”的行为。每个决策点必须显式生成可选工序掩码DQN 选择时对不可选动作的 Q 值直接置为负无穷。这个 bug 我一度排查了两天表现为训练曲线一直抖动最后打印每个决策点的 Q 值才定位到问题。第二个坑是 Q 值过估计。标准 DQN 用 max 算子自举天然会高估 Q 值在调度这种长期回报延迟的问题里会被放大。解决方式是 Double DQN——用主网络选动作、目标网络估价值。改动只有几行收益非常明显建议默认开启。第三个坑是回放缓冲区污染。如果往缓冲区里塞大量来自同一个订单结构的经验模型会过拟合到那一类订单泛化能力骤降。训练集订单要尽量随机生成覆盖不同的加工时间分布、不同数量的工件和设备。4. PPO 在车间调度中的应用实战4.1 从“猜 Q 值”到“直接出策略”PPO 的思路差异PPO 是策略梯度家族的集大成者。它不再去估计“哪个动作价值高”而是直接让策略网络输出动作的概率分布用带裁剪的代理目标函数做更新先以当前策略采样一批完整轨迹计算每个状态动作的优势函数用 GAE 估计而不是只看即时奖励更新策略让“好的动作”概率上升、“坏的动作”概率下降但用裁剪系数限制单步更新幅度避免策略跳变。在调度场景中DQN 和 PPO 的直接差别体现在训练范式上DQN 依赖经验回放样本利用率高但更新依赖 Q 值估计PPO 是 on-policy每条样本用完就丢理论上样本效率低但策略更新更稳对大状态空间和随机性更强的调度环境更鲁棒。在多个模拟场景里的实际体验是小规模比如 6 个工件 6 台设备时 DQN 训得更快规模一上去15 个工件以上PPO 的稳定性和最终效果全面占优而且 PPO 对奖励尺度的敏感度比 DQN 低很多。4.2 Actor-Critic 结构与调度动作采样PPO 用两个网络Actor 输出策略分布 π(a|s)Critic 输出状态价值 V(s)两个网络通常共享底层特征提取层各自再接不同的输出头。调度场景下Actor 的输出是一个长度等于动作候选数的 logits 向量经过 Softmax 变成概率分布再按这个分布采样动作。注意一个细节非可选动作的 logits 也要在 Softmax 之前设为负无穷否则即使概率很小偶尔采到非法动作也会破坏仿真流程。采样策略里我建议推理阶段不用贪心采样而是保持从概率分布采样只是临时把温度系数调低。因为调度是个多解问题保留一定的随机性反而能让最终方案跳出局部最优实测在完工时间指标上概率采样比 argmax 平均好 3%~5%。实操体会PPO 在调度里真正值钱的地方不是动作精度而是策略分布本身。它学到的不是“哪道工序最优”而是“在什么状态下哪些工序组合值得优先考虑”——这更接近人工调度的思路。4.3 从离散动作到连续动作调度规则参数化扩展PPO 最大的扩展空间在于它天然支持连续动作空间。如果你不想让网络直接选工序可以让它学“如何组合调度规则”比如输出三个权重分别对应最短工时优先、最早交期优先、最长总加工时间优先决策逻辑变为“候选工序的综合得分 w1 × 工时 w2 × 交期 w3 × 总工时”选综合得分最低的工序上机。这种设计的好处是动作从“选哪个工件”变成“调哪组参数”动作维度恒定且可解释对生产管理人员来说更容易接受。更重要的是它让策略从一个固定规则的执行器变成了规则生成器泛化能力强了不少。我自己在一个持续多天的模拟排产实验里用这种方法训练出的策略比单一 SPT 规则平均完工时间缩短约 11%且对订单结构变化更不敏感。4.4 PPO 超参数与稳定性经验PPO 虽然比 DQN 稳但超参数敏感度依然很高列一张我调了几个版本的推荐表超参数推荐范围说明裁剪系数 ε0.1~0.30.2 是默认值调度任务里 0.15 更稳GAE 系数 λ0.9~0.97影响优势估计的偏差-方差权衡每轮采集步数2048~8192调度轨迹短建议取大值减少方差Critic 学习率Actor 的 2 倍价值网络要更快收敛熵系数0.005~0.01太小探索不足太大策略随机更新轮数5~10每批数据重复使用次数太多会过拟合还有一个容易被忽略的点调度环境的奖励分布往往严重偏斜。同样一张订单表人为排得差可能耗时 200 小时排得好只要 150 小时。方差一大优势估计就容易失真。我的处理方式是每个 episode 结束后对奖励做 min-max 归一化再进入 GAE 计算收敛速度会有可感知的提升。5. 实操记录环境搭建、训练对比与性能评估5.1 仿真环境怎么搭才不像玩具我见过很多人用极简仿真器做强化学习调度比如把加工时间写成固定矩阵事件推进用简单 for 循环。这种环境训练出来的策略拿到真实车间基本废掉。我的建议是把环境至少做成这样事件驱动的时间推进维护一个最小堆记录每台设备的完工时刻和工序释放时刻每次决策点就是堆顶事件发生时刻随机扰动开关保留“设备故障概率”“加工时间波动系数”两个参数入口用于后期评估策略鲁棒性动作执行校验每个动作执行前校验前置工序是否完成、设备是否空闲不满足就直接返回非法动作标记数据记录接口每个 episode 记录每一步的局部状态和全局状态便于事后回溯训练曲线。环境用一个纯 Python 事件队列就能写几千行内能搞定没必要上一整套商业仿真软件。重点是接口要跟训练框架解耦方便后续替换环境来测试泛化。5.2 一次完整实验的配置与执行流程我拿一个模拟场景来举例场景名我记作“模拟订单组一”10 个工件、5 台设备、每工件 4~6 道工序加工时间在 10~60 之间随机生成交期按“最短加工总和的 1.5 倍”设定。规则基线采用“最短工时优先 最早交期优先”的组合规则元启发式基线采用遗传算法种群 100迭代 200 代作为离线参考。训练流程分三步走第一步先训练一个小规模代理版本6×6 场景把动作掩码、奖励归一化、网络结构全部调通再上完整 10×5 场景。这一步能节省大量调试时间。第二步DQN 和 PPO 各训练 5000 个 episode每 100 个 episode 用固定的测试订单集评估一次策略记录 makespan 和决策耗时。第三步把训练好的策略分别在“与训练分布一致”的订单和“完全新分布”的订单加工时间变为 5~80交期系数变为 2.0上做泛化测试。5.3 DQN 与 PPO 的实测结果对比我做了两次完整的对比实验结论基本一致整理成下面的对比表数值来自我当时实验记录仅代表该场景下的相对表现对比维度DQNPPO小规模收敛速度快3000 episode 左右稳定相对慢需要 4500 左右小规模最终 makespan与规则基线接近偶有 3% 优势比规则基线好 5%比 DQN 好 2%大规模稳定收敛抖动明显需要反复调参训练曲线平滑一次到位对新订单分布泛化遇到新分布时性能退步明显仍能保持原性能的 90% 左右单次决策耗时毫秒级毫秒级略慢于 DQN实现难度简单改动少组件多调参环节多这个结果很符合两类算法的理论差异DQN 依赖 Q 值函数逼近状态空间一大、分布一变值函数误差就会爆炸PPO 学的是策略分布不同分布之间策略结构相似相对更容易迁移。5.4 性能评估指标怎么定调度问题最常看的指标是最大完工时间makespan但实际生产里光看这一个远远不够。我建议在训练和评估时同时记录四个指标makespan最后一个工件完工时间代表“计划整体长度”加权延迟率超过交期的工件的延迟时间加权和直接反映客户满意度设备平均利用率所有设备加工时间占总可工作时间的比例太低说明排产有闲置浪费决策方差同一策略在相同订单上的多次调度结果差异衡量策略稳定性。评估时重点不是看绝对数字而是看“相对基线的提升率”。比如同一订单组规则基线 makespan 是 180 小时RL 策略是 165 小时那提升率就是 8.3%。这个数字比绝对时间更能说明问题因为不同订单组的绝对时间没法横向比。6. 常见问题与排查技巧实录6.1 训练不收敛先检查这三个地方我遇到过的“不收敛”案例八成最后都能归到三个根因。第一奖励尺度不对。如果奖励数值动辄几百上千梯度更新就会像在狂风里走钢丝。把单步奖励和回合奖励先做统计归一化让数值保持在个位数量级绝大多数收敛问题会消失。第二动作掩码失效。某个决策点把不可选动作漏放了网络学到“选一个逻辑上不可能的工序”环境只能报错或者给一个极差的奖励整个训练过程被严重干扰。建议在环境里加一行断言逻辑——任何时刻合法动作集合必须非空且不包含已释放工序。第三探索策略失衡。DQN 的 epsilon 衰减太快模型过早进入纯利用状态把刚开始的次优行为固化下来。PPO 则是熵系数太小策略过早收敛到某个局部最优。出现训练曲线长期水平、没有上升趋势时先回头检查探索策略再调网络结构。6.2 奖励被“钻空子”模型找到了你没发现的规则这是强化学习在调度里最容易出现的“意外”。我的一个模拟场景里奖励函数包含“工序完成时间越短越好”的项训练出的策略开始大量选择加工时间最短的工件哪怕它是一个无关紧要的支线工件导致主线工件全部积压总完工时间反而变长。排查方法是做“策略行为审计”把训练好的策略在每个状态下的动作选择打印出来对比人工直觉判断。一旦发现策略在某个维度上过度聚焦基本就是奖励函数权重有偏差。解决办法是加约束项比如对“重要工件剩余工序最多或总工时最大的等待时间”单独设置惩罚让模型没法通过牺牲主线来换取任务完成率。奖励工程在调度系统里永远是投入产出比最高的部分。6.3 从仿真到生产现场落地时的四个工程化问题训练完的模型从仿真器搬到实际生产系统还要过几道坎状态特征对齐仿真环境里定义的状态特征到了制造执行系统里能不能实时拿到要提前确认数据接口和采集频率冷启动问题现场很难先跑 5000 个 episode 试错。我的做法是让 RL 策略在前面 200 个决策里用“RL 策略 规则兜底”的混合策略RL 输出可信再加权采用否则用规则人机协作边界调度员担心“黑盒策略不可解释”。给策略动作加上“推荐理由”输出层记录每个候选工序的权重贡献后现场接受度高了很多策略回滚生产线上永远要留一个规则路径作为 fallbackRL 策略出现明显异常时一键切回。这个建议不只是工程师视角也是管理层最看重的东西。6.4 快速排查速查表症状优先排查项常用解法训练曲线震荡不下降奖励尺度、学习率、动作掩码奖励归一化学习率降到 1e-4打印掩码校验策略总选同类工件奖励函数偏置、状态特征缺失加约束惩罚项补充交期/总工时特征小规模好、大规模崩状态特征维度不足、网络容量不够加隐藏层宽度引入设备负载聚合特征上线后效果不如仿真状态特征采集缺失、环境随机性被忽略在仿真环境里加扰动再重新评估PPO 训练假死熵系数为 0、GAE 优势全为负熵系数设 0.01奖励做 min-max 归一化最后再聊一点个人体会。我自己的切身感受是DQN 和 PPO 没有绝对的谁优谁劣更多是场景匹配问题。项目前期、小规模、想快速验证一个调度决策点能不能用强化学习改善DQN 是性价比最高的起点一旦涉及大规模、多目标、动态扰动频繁的场景花时间在 PPO 上是值得的它的稳定性换来的调试时间节省远超前期多写的那些网络代码。再分享一个小技巧无论用哪个算法先把规则基线SPT EDD的结果存成档案让每个训练好的 RL 策略都跟这个档案做对照这不仅帮你判断策略是否真的有价值也能在跟业务方汇报时拿出让人信服的“提升率”数字。调度优化的路很长但把每一步决策流程记录清楚剩下的就是耐心的迭代。
阅读完成 · 觉得有帮助?
咨询建站