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

MATLAB实现Q-Learning迷宫路径规划:从环境建模到策略收敛

MATLAB实现Q-Learning迷宫路径规划:从环境建模到策略收敛 ★ FEATURED ARTICLE
简介这份资源面向强化学习入门者与需要动手复现经典算法的学习者提供Q-Learning算法的Matlab完整实现与逐行中文注释帮助读者在无模型环境下理解决策策略的学习过程。代码以16×1网格世界为实验场景王子需避开障碍物与陷阱、抵达第16格的公主涵盖可移动矩阵TT、奖赏矩阵R、Q矩阵初始化、折扣因子gamma与epsilon-greedy策略选择并演示贝尔曼方程更新Q值、900轮训练循环及训练后最优路径规划注释细致便于对照理解每一步逻辑。资源包共1个doc文件大小约33KB内容紧凑、开箱即用。目前已有1380人学习下载适合希望从代码层面吃透Q-Learning基本流程、并可直接运行调试的读者参考。1. 从一份 16 格迷宫说起为什么用 Q-Learning 交强化学习课设很多同学做强化学习课设第一反应是找个现成框架跑个 CartPole结果答辩时被问“状态转移矩阵长什么样”“奖励怎么设计的”就卡住了。这份 MATLAB 版 Q-Learning 源代码走的是另一条路不依赖任何工具箱用 16 个状态、四个动作、一张手写的可移动矩阵把无模型决策的完整闭环摊开给你看。它适合两类人——要交强化学习课设、毕设需要一份能讲清原理又能跑出路径的学生以及想快速验证奖励设计思路的从业者。整套代码不到百行但环境建模、Q 值更新、epsilon-greedy 策略、路径回溯一个不少属于那种“麻雀虽小、五脏俱全”的参考实现。2. 环境建模16 状态网格怎么变成可计算的矩阵Q-Learning 的第一步从来不是写更新公式而是把“世界”翻译成矩阵。这份代码最值得抄的地方就是它用三个矩阵把迷宫讲清楚了可移动矩阵T描述“能不能走”奖赏矩阵R描述“走了值多少”Q 矩阵描述“学到的经验”。三者维度一致都是 16×16状态编号 1 到 16 对应网格位置动作则直接编码成“目标状态编号”这个设计省掉了单独的动作表是整份代码最巧妙的一处。2.1 状态编号与动作编码的对应关系代码把 16 个格子按行优先编号1 到 4 是第一行5 到 8 第二行依此类推。四个动作 N/S/W/E 分别对应编号减 1、加 1、减 4、加 4。这种“动作即目标状态”的编码方式让T(i,j)1直接表示“从 i 能一步到 j”后续选动作时find(T(state,:)1)就能拿到所有合法后继不需要再维护一张动作映射表。% 定义可移动矩阵 TT(i,j)1 表示可从 i 一步移动到 j T zeros(16); for i 1:16 % 上行动作 N不在第一行才能向上 if ~ismember(i, [1,5,9,13]) T(i, i-1) 1; end % 下行动作 S不在最后一行才能向下 if ~ismember(i, [4,8,12,16]) T(i, i1) 1; end % 左行动作 W编号大于 4 才能向左 if i 4 T(i, i-4) 1; end % 右行动作 E编号小于 13 才能向右 if i 13 T(i, i4) 1; end end这段循环的含义是先假设所有格子都能四向移动再用边界条件把越界动作砍掉。ismember(i,[1,5,9,13])判断是否在第一行是则不能向上i4判断是否不在第一行是则能向左。参数上唯一要改的是网格尺寸如果换成 5×5边界判断里的行首行尾编号和i±5的步长都要同步调整否则矩阵会错位。2.2 障碍物、跳跃与奖赏矩阵的设计基础移动定义完后代码用三行覆盖式赋值把“地形”改了T(:,[10,11,14])0把第 10、11、14 号格子设为不可进入相当于障碍物T(13,:)0清空 13 号格子的所有出边再单独T(13,15)1开一条跳跃通道。这种“先全连、再切断、最后补特殊边”的写法比逐个 if 判断可读性高得多改地图时只需要动这几行。奖赏矩阵R的设计更值得琢磨。代码先R-1*ones(16)把所有转移设为 -1意思是“每走一步都有代价”这会逼着智能体找最短路径然后R(:,6)0让进入 6 号格子的奖励归零R(:,7)-5把 7 号设为陷阱R(:,16)10让到达 16 号公主位置拿到最大奖励R(13,15)5给跳跃通道一个中等奖励。注意R(:,6)0用的是整列赋值表示“任何状态进入 6 都拿 0”这和R(6,:)完全不同前者是入边奖励后者是出边奖励写反了学习目标就变了。提示奖赏矩阵按“目标状态”索引即R(s,a)中 a 是动作后的状态。这是本实现的核心约定改奖励时务必沿列方向改。3. 训练循环epsilon-greedy 与贝尔曼更新的落地细节环境搭好后学习过程其实就三件事选动作、更新 Q、换状态。这份代码的训练循环外层跑 900 个 episode内层用while state~16一直走到终点结构非常干净。真正容易翻车的是几个数值和策略细节下面拆开讲。3.1 随机初始化与障碍物规避每个 episode 开始时代码用unidrnd(16)随机选起点再用一个while ismember(state,[10,11,14])循环把落在障碍物上的起点重抽。这个细节很多人会漏结果智能体一开局就卡在障碍物里内层循环永远出不来程序直接挂死。for episode 1:900 % 随机化初始状态并避开障碍物 state unidrnd(16); while ismember(state, [10,11,14]) state unidrnd(16); end % 未到终点则持续决策 while state ~ 16 ... end endunidrnd是 MATLAB 统计工具箱里的均匀整数采样函数如果环境没装工具箱可以换成randi(16)行为一致。900 这个数字不是硬性要求网格小、奖励稀疏时 500 到 1000 都能收敛判断标准是路径稳定不再变化而不是死记次数。3.2 epsilon-greedy 选择与 Q 值更新公式内层循环先find(T(state,:)1)拿到所有合法后继再取对应的 Q 值possible_Q。然后按rand()epsilon分流小于 0.3 就随机探索否则选 Q 最大的动作。这里epsilon0.3意味着三成概率乱走、七成概率走当前最优前期保证探索、后期靠贪心收敛。possible_actions find(T(state,:) 1); possible_Q Q(state, possible_actions); if rand() epsilon % 探索随机选一个合法动作 choose unidrnd(length(possible_actions)); action possible_actions(choose); else % 利用选当前 Q 值最大的动作 [~, index] max(possible_Q); action possible_actions(index); end % 贝尔曼更新即时奖励 折扣后的未来最大 Q Q(state, action) R(state, action) gamma * max(Q(action, :)); state action;更新公式Q(s,a) R(s,a) gamma * max(Q(a,:))是标准的单步 Q-Learning。gamma0.8表示未来奖励打八折值越接近 1 越看重长远越接近 0 越短视。注意这里用的是max(Q(action,:))而不是max(Q(state,:))因为动作已经执行新状态是action取的是新状态下所有出边的最大 Q。写错成Q(state,:)是新手最常见的 bug表现为 Q 值不收敛、路径绕圈。3.3 训练监控与路径回溯训练过程中每 100 次打印一次进度属于最低成本的监控手段。真正交付时要看的是 Q 矩阵是否稳定可以加一句norm(Q - Q_old)观察变化量。训练结束后路径回溯从起点开始每步取max(Q(start_0,:))对应的下一状态直到走到 16。start_0 1; % 设置起点 path start_0; % 路径向量初始含起点 while path(end) ~ 16 [~, next] max(Q(start_0, :)); path [path, next]; start_0 next; end disp(path)这段回溯是纯贪心没有探索所以能直接反映学到的策略。如果path出现重复状态或死循环说明 Q 矩阵还没收敛或者某条边的奖励设计让智能体更愿意绕路。实际调试时我一般会先把gamma调到 0.9、epsilon调到 0.1 再跑一轮对比路径是否一致两次结果相同才认为策略稳定。4. 避坑与排查这份代码最容易翻车的五个点代码短不代表没坑恰恰因为短每个细节都直接决定能不能跑通。下面五条是这类网格 Q-Learning 实现里最高频的问题按“现象 → 原因 → 解决”整理照着排查基本能定位。4.1 起点落在障碍物导致死循环现象是程序卡在训练循环里不动CPU 占满但没有任何输出。原因是随机初始化没有排除 10、11、14 号格子while state~16永远不满足。解决办法就是代码里那个while ismember(state,[10,11,14])重抽循环缺了它必挂。更稳妥的做法是把合法起点单独存成向量用datasample或randi索引避免反复重抽。4.2 Q 更新用错状态维度现象是训练几百轮后路径仍然乱跳或者 Q 值整体不增长。原因是把max(Q(action,:))写成了max(Q(state,:))等于用旧状态的最优值更新贝尔曼方程的自洽性被破坏。排查方法是打印单步更新前后的 Q 值看新状态的最大 Q 是否被正确引用。修正后 Q 值应随 episode 单调趋稳。4.3 奖赏矩阵行列写反现象是智能体明明到了 16 号却不拿奖励或者疯狂往 7 号陷阱里钻。原因是R(:,16)10被写成R(16,:)10前者是“进入 16 奖励 10”后者是“从 16 出发奖励 10”语义完全相反。检查方法是看R的非 -1 元素分布正确情况下 10 应该在第 16 列。4.4 epsilon 固定不衰减导致策略抖动现象是路径每次运行都不一样答辩演示时结果不可复现。原因是epsilon0.3全程不变训练后期仍有三成概率乱走Q 值一直在小幅震荡。通常的做法是让 epsilon 随 episode 线性衰减比如epsilon max(0.05, 0.3 * (1 - episode/900))前期多探索、后期多利用路径会明显稳定。4.5 跳跃通道破坏连通性现象是某些起点永远到不了终点或者路径长度异常。原因是T(13,:)0清空了 13 号格子的所有出边只留T(13,15)1如果起点在 13 附近且没有其他通路就会困死。排查时用graph或邻接矩阵做一次连通性检查确认从每个合法起点都能到达 16再开始训练。注意改地图后务必重跑连通性检查这是血泪经验跳过这一步的调试时间往往比写代码还长。5. 验收与答辩怎么证明这套 Q-Learning 真的学到了课设验收和工程交付不一样老师或评审看的不是你代码多优雅而是你能不能证明“学习确实发生了”。我的习惯是准备三样东西一张收敛曲线、一组对比路径、一份参数敏感性表。收敛曲线用每个 episode 的步数或累计奖励画横轴 episode、纵轴步数正常情况应该从高位震荡逐步下降到稳定值如果一直不降说明奖励或更新公式有问题。对比路径则是固定起点分别用训练前Q 全零和训练后的 Q 矩阵回溯前者基本是乱走或原地打转后者应该是干净的最短路径这个对比最能说明问题。参数敏感性表可以按下面这个结构准备答辩时被问“gamma 为什么取 0.8”直接翻表参数取值观察到的现象结论gamma0.5路径偏短视愿走陷阱抄近路折扣过强不推荐gamma0.8路径稳定避开 7 号陷阱本场景合适gamma0.95收敛变慢前期绕路多需更多 episodeepsilon固定 0.3路径偶有抖动可复现性差epsilon线性衰减路径稳定可复现推荐做法答辩时还有一个高频追问“为什么不用 SARSA”回答抓住一点即可——Q-Learning 是 off-policy更新用max直接逼近最优策略SARSA 是 on-policy更新用实际采取的下一动作在陷阱密集的环境里 SARSA 更保守、Q-Learning 更激进。这份代码的奖励设计陷阱 -5、终点 10适合 Q-Learning 的激进风格换成 SARSA 也能跑但路径可能更绕。被问到“900 次够不够”不要答“够”要答“看 Q 矩阵变化量连续 100 轮norm小于阈值就认为收敛900 只是本场景的经验值”。最后说个我自己的教训早年交这类课设我只贴了最终路径图结果被问“你怎么知道它不是碰巧走对的”当场答不上来。从那以后我每次做强化学习 demo都强制走一遍“训练前 vs 训练后”的对比回溯再附一张步数收敛曲线两个证据一摆基本没人再质疑学习是否发生。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站