尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MATLAB强化学习入门:用Q-Learning实现迷宫路径规划与调参实践

MATLAB强化学习入门:用Q-Learning实现迷宫路径规划与调参实践 简介面向对强化学习感兴趣的初学者以及路径规划方向的研究人员这份基于MATLAB的Q-Learning迷宫路径规划资源以迷宫逃脱为典型场景首先讲解通过试错更新Q表来逼近最优策略的基本原理再系统演示从环境建模、Q表初始化与更新规则设定到智能体策略学习与最优路径输出的完整流程非常利于快速建立强化学习整体认知。压缩包共包含593个文件其中以.m源码文件为主481个并配有.mat实验数据、.fig结果图、.txt说明、.c/.cpp及MEX辅助函数、.pdf参考资料等多种类型压缩包整体仅7.32MB结构组织清晰便于按需查阅。目前已有314人学习下载。除可直接运行的Matlab迷宫路径规划源码外还提供了参数配置示例、环境规则自定义说明、运行日志与可视化图表帮助直观理解Q值迭代与收敛过程同时附有算法优化、多智能体融合及实际应用等拓展建议对初学者深入掌握Q-Learning和研究者开展相关实验均有很高的参考价值。1. 用一张奖励表教会机器走迷宫Q-Learning 在 MATLAB 中的最小落地闭环如果只用 30 行 MATLAB 代码就能让一个智能体在网格迷宫里从起点走到终点期间不写任何神经网络、不调用深度学习工具箱你会不会觉得强化学习其实离日常开发没那么远这就是 Q-Learning 的魅力它用一张二维表格存放“状态—动作”的长期价值估计靠反复试错更新这张表最后收敛出一套从起点到终点的最优策略。相比深度强化学习动辄需要 GPU、经验回放和上千轮训练Q-Learning 在状态空间可枚举的离散场景里反而更稳、更快、更好调试——迷宫路径规划正是它的经典主战场。这篇文章会从 Q 表更新的数学原理讲起然后直接用 MATLAB 手写一个不需要额外工具箱的完整迷宫训练脚本给出奖励矩阵、衰减因子、探索率这几个关键参数的合理区间和调参依据再对比 Reinforcement Learning Toolbox 里rlQAgent的标准做法最后讲清训练曲线的判定精度和可视化方案。适合两类人一是刚接触强化学习、想在 MATLAB 里看真实迭代过程的入门者二是已经在做路径规划、想换个思路绕过 A* 或 RRT 的工程师。2. Q-Learning 的原理与迷宫建模先把 Q 表、奖励与状态转移说清楚2.1 为什么迷宫路径规划适合用 Q-Learning迷宫路径规划本质上是一个“有限状态、有限动作、带延迟奖励”的序贯决策问题。智能体每一步只做四个动作之一上、下、左、右它所在的位置就是状态走到终点获得正奖励撞墙或走入死胡同获得负奖励或零奖励。Q-Learning 的核心优势在于它不需要环境的动态模型——也就是说智能体不需要提前知道哪条路通、哪条路堵它只需要在每一步“试一下”然后根据实际返回的奖励和新位置更新 Q 表。这与 A* 这类需要完整地图先验知识的规划算法有本质区别A* 是“看全图再规划”Q-Learning 是“走一步看一步再学习”。对于网格规模在 10×10 到 30×30 之间的迷宫状态空间大小是网格数乘动作数即几百到几千的量级。Q 表在这个规模下完全可以放进内存训练几百个 episode 就能收敛。如果迷宫更大或者状态变为连续空间Q 表就会爆炸那时才需要考虑 DQN 或策略梯度——但那是另一个话题了。2.2 Q 值更新公式的直观理解Q-Learning 的更新公式是Q(s,a) ← Q(s,a) α * [r γ * max_a Q(s,a) - Q(s,a)]翻译成工程师语言当前状态s下执行动作a得到一个即时奖励r并转移到新状态s。新状态s下能拿到的最大未来回报是max_a Q(s,a)。把即时奖励和衰减后的未来回报加起来就是这次尝试的“现实目标值”减去当前 Q 表里存的“估计值”得到时间差分误差再乘以学习率α修正原来的估计。四个参数的作用要记牢α学习率控制新信息覆盖旧信息的速度γ折扣因子控制远期回报的价值——γ越大智能体越有远见γ越小则只顾眼前ε探索率控制随机动作的比例ε大则多探索、ε小则多利用已有经验。它们不是随便填的α建议取 0.1 到 1 之间迷宫问题常用 0.5 到 1 让收敛更快γ建议取 0.9 到 0.99因为终点奖励要传播回起点需要足够的衰减延迟ε一般从 0.9 或 1 开始随训练进程衰减到 0.01 左右。2.3 MATLAB 中迷宫地图的两种表示方法最常见的表示方法是数字矩阵0表示可通行空地1表示墙壁2表示终点也可以单独用终点坐标。例如一个 5×5 的迷宫maze [ 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 2 ];这种表示法直观且容易可视化用imagesc或pcolor画出来就是一张格子图。另一种表示法是预计算状态转移表把每个格子的四个方向写成next_state transition(current_state, action)遇到边界或墙时next_state等于当前状态原地不动同时给一个惩罚奖励。第二种方法效率更高因为训练循环里不需要反复判断坐标是否越界缺点是迷宫改起来要重新生成转移表。2.4 奖励函数的设计原则奖励函数决定学习方向。常见的设计是三值奖励空地行走给0或一个小负值比如-0.1防止绕路撞墙给-1或不给奖励到达终点给10。-0.1这种“时间惩罚”在迷宫问题里非常有效它会在 Q 表里制造梯度——智能体倾向于找到最短路径而不是在空地上转圈。如果空地奖励是 0所有非终点路径的价值会一样策略可能收敛到一条绕远路但同样能到终点的路径这在路径规划里是不能接受的。2.4.1 MATLAB 里实现奖励计算的推荐写法function [next_state, reward, done] step(maze, state, action, end_idx) % 动作编码: 1上, 2下, 3左, 4右 [rows, cols] size(maze); [r, c] ind2sub([rows, cols], state); dr [-1 1 0 0]; dc [0 0 -1 1]; nr r dr(action); nc c dc(action); if nr 1 || nr rows || nc 1 || nc cols || maze(nr, nc) 1 next_state state; % 撞墙原地不动 reward -1; done false; else next_state sub2ind([rows, cols], nr, nc); reward -0.1; % 时间惩罚 done false; if next_state end_idx reward 10; done true; end end end这个函数的逻辑很直白先把线性索引转成行列坐标ind2sub根据动作查表得到方向增量判断是否越界或撞墙。撞墙时状态不变、奖励为-1不会让智能体通过反复撞墙刷奖励走到终点返回10并把done置为true训练循环跳出当前 episode。函数拆出来而不是写在主循环里是为了后面换rlQAgent时能直接复用环境逻辑。3. 手写 MATLAB Q-Learning 训练循环从零实现不依赖工具箱的迷宫逃脱3.1 主框架episode 循环与 step 调用的标准写法不依赖任何工具箱的实现核心就是一个双层循环外层遍历 episode内层遍历每一步。每一步选择动作ε-greedy 策略、执行step更新 Q 表、记录路径用于可视化。下面给出一个可以直接跑的完整脚本框架%% 参数配置 maze [0 1 0 0 0; 0 1 0 1 0; 0 0 0 1 0; 0 1 0 0 0; 0 1 1 0 2]; [rows, cols] size(maze); start_idx 1; % 起点是左上角 end_idx find(maze 2); % 找到终点索引 n_states rows * cols; n_actions 4; Q zeros(n_states, n_actions); alpha 0.5; gamma 0.9; epsilon 0.9; epsilon_min 0.01; epsilon_decay 0.995; episodes 500; max_steps 100; %% 训练 for ep 1:episodes state start_idx; total_reward 0; step_count 0; while true % ε-greedy 动作选择 if rand epsilon action randi(n_actions); else [~, action] max(Q(state, :)); end % 执行动作 [next_state, reward, done] step(maze, state, action, end_idx); % Q 值更新 best_next max(Q(next_state, :)); Q(state, action) Q(state, action) alpha * ... (reward gamma * best_next - Q(state, action)); state next_state; total_reward total_reward reward; step_count step_count 1; if done || step_count max_steps break; end end % 探索率衰减 epsilon max(epsilon_min, epsilon * epsilon_decay); % 每隔 50 个 episode 打印一次进度 if mod(ep, 50) 0 fprintf(Episode %d, total reward: %.2f, steps: %d, epsilon: %.3f\n, ... ep, total_reward, step_count, epsilon); end end这段代码的核心逻辑集中在while true循环里。动作选择用rand epsilon判断要不要随机探索否则从 Q 表的当前行取max对应的动作Q 值更新严格按时间差分公式展开先取next_state下的最大 Q 值作为best_next再乘gamma、加reward最后乘alpha修正回原值。代码末尾的探索率衰减很重要——如果不衰减智能体永远在随机乱走Q 表虽然也会收敛但需要多 5 到 10 倍的时间步。3.2 直接用max还是用randperm处理并列最大 Q 值max(Q(state, :))返回第一个最大值对应的索引。如果 Q 表里多个动作的 Q 值恰好相等初始时全部为 0max会固定选择第一个动作这会导致早期策略严重偏向一个方向。处理办法有两种一是用find找出所有最大值的索引再随机挑一个二是给 Q 表加一个小的随机扰动后再选。第二种做法在深度强化学习里叫 action noise在网络初始化随机的情况下没必要但在 Q 表场景下很有效。best_actions find(Q(state, :) max(Q(state, :))); action best_actions(randi(numel(best_actions)));建议在训练初期前 50 个 episode使用随机打破并列后期直接用max加快决策速度。因为训练后期各动作 Q 值差距明显并列的概率本身就很低。3.3 训练过程的 3 个关键指标训练是否正常不能只看最终能不能到达终点还要看中间过程。三个指标按重要性排序每 episode 总步数理想曲线是整体下降趋势前期波动大、后期稳定在最短路径长度附近。如果步数一直下不去先看探索率衰减是否太慢。每 episode 总奖励因为每步都有-0.1的时间惩罚总奖励会随步数减少而上升。终点奖励 10、时间惩罚 -0.1最短路径若为 8 步则总奖励约10 - 0.8 9.2。这个数值可以作为收敛基准。是否频繁重复访问同一格这个需要在记录路径后手动分析如果同一路径反复横跳说明时间惩罚设置得太小-0.1可以改成-0.5再试。3.4 表格迷宫 Q-Learning 必调参数速查表参数推荐范围迷宫问题常用值调大后效果调小后效果学习率 α0.1 10.5收敛快但震荡大收敛慢但稳定折扣因子 γ0.9 0.990.9更重视远期回报目光短浅探索率 ε 初值0.5 10.9前期探索充分过早利用ε 衰减系数0.9 0.9990.995衰减慢训练久衰减快易陷局部时间惩罚-0.01 -1-0.1路径更短路径可能绕路这个表是具体调参时的起点。迷宫规模小比如 5×5ε 可以衰减快一些0.98 就够迷宫大20×20 以上ε 衰减要放慢到 0.999否则智能体还在摸索阶段就过早进入利用模式容易卡在局部最优。3.5 可视化与路径提取用 imagesc 画轨迹训练完成后提取最优策略本身就很简单从起点出发每次查 Q 表取最大 Q 值对应的动作执行到终点为止。这个过程中要把每一步经过的位置记录下来然后用imagesc画出来%% 提取最优路径 state start_idx; path state; while state ~ end_idx [~, action] max(Q(state, :)); [next_state, ~, done] step(maze, state, action, end_idx); state next_state; path [path; state]; if done break; end end %% 可视化 figure; imagesc(maze); colormap(gray); hold on; [path_r, path_c] ind2sub([rows, cols], path); plot(path_c, path_r, r-o, LineWidth, 2, MarkerSize, 6); title(Q-Learning 迷宫最优路径);可视化时的注意点imagesc的坐标轴原点在左上角而 MATLAB 的矩阵索引(i,j)也是从左上开始因此行列坐标和图形坐标方向一致不需要 reverse。plot里横坐标是列号、纵坐标是行号和imagesc默认坐标一致。路径绘制时要确保起点和终点在图上有明显的标记可以用scatter单独标一下。4. 用 Reinforcement Learning Toolbox 复现并对比手写版4.1 什么时候该换工具箱手写版的优势是逻辑透明、无依赖、方便教学缺点也很明显没有内置的经验回放、没有自动超参搜索、没有训练进度可视化。如果你的目标是快速验证一版算法、或者作为正式项目的前期原型手写版足够了。但如果后续要扩展到连续动作空间、要对比 DQN 或 PPO或者要产出带训练曲线的标准报告用 MathWorks 的 Reinforcement Learning Toolbox 更省事。rlQAgent是工具箱里的内置 Q-Learning 智能体它可以直接吃rlMDPEnv或自定义环境训练过程用train函数统一驱动。4.2 基于 rlQAgent 的完整训练与评估代码%% 定义迷宫环境 maze [ 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 2 ]; [rows, cols] size(maze); start_state 1; end_state find(maze 2); getState (obs) obs(1); % 取观测中的状态分量 env rlMDPEnv( ... ObservationInfo, rlFiniteSetSpec(1:rows*cols), ... ActionInfo, rlFiniteSetSpec([1 2 3 4])); % 直接使用上面手写的 step 函数作为环境转移函数 env.StepFunction (obs, action) stepWrapper(maze, obs, action, end_state); %% 定义 QAgent agentOpts rlQAgentOptions( ... DiscountFactor, 0.9, ... EpsilonGreedyExploration, true, ... Epsilon, 0.9); agent rlQAgent(agentOpts); %% 训练 trainOpts rlTrainingOptions( ... MaxEpisodes, 300, ... MaxStepsPerEpisode, 100, ... StopTrainingCriteria, AverageReward, ... StopTrainingValue, 9.0, ... Verbose, true); trainStats train(agent, env, trainOpts);这里的关键点有两个。第一rlMDPEnv要求环境的StepFunction能接收观测作为 obs和动作我们需要写一个stepWrapper把 obs 转成状态索引再调用前面手写的step函数这样环境逻辑完全复用不需要重新定义转移矩阵。第二rlQAgentOptions里的Epsilon在训练过程中会由工具箱内置逻辑自动衰减衰减策略在官方文档里说明是随 episode 逐步降低但实际衰减幅度不如手写版的epsilon_decay可定制。所以手写版适合需要精细控制训练过程的场景工具箱版适合快速出结果。4.3 rlMDPEnv 与手写循环的速度和灵活性对比工具箱版本最大的成本在环境接口转换和内部训练流程的封装开销。在 5×5 小迷宫上手写版 500 个 episode 大约 0.5 秒跑完工具箱版可能需要 3 到 5 秒差别来自每次 step 的对象传递和训练统计记录。但工具箱版免费赠送了训练曲线绘图、自动保存模型、多 episode 平均奖励统计等能力手写版这些都要自己写。实际项目里没有绝对好坏关键看你的交付物是什么如果只是要一条最优路径和 Q 表手写版如果要给非技术同事汇报训练过程和收敛曲线工具箱版。5. 调参避坑与实际应用从收敛判定到复杂迷宫泛化5.1 收敛判定的正解不是步数不变而是策略稳定很多初学者的误区是看到某一次 episode 的步数达到最短路径长度就认为训练完成。实际上单次 episode 有偶然性可能这次运气好、下次就绕路。正确的收敛判定是在连续 50 到 100 个 episode 内提取出的最优路径完全一致并且不再出现随机探索改道路径的情况。可以用下面的代码片段自动判定path_history zeros(episodes, 1); % 训练结束后单独评估, epsilon 置 0 epsilon 0; for ep 1:episodes state start_idx; count 0; while state ~ end_idx count max_steps [~, action] max(Q(state, :)); [state, ~, done] step(maze, state, action, end_idx); count count 1; if done, break; end end path_history(ep) count; end if all(path_history path_history(1)) fprintf(策略已收敛到稳定路径\n); end这里关键是把epsilon置 0只用贪心策略评估排除探索带来的随机步数变化。如果连续评估的步数序列稳定说明 Q 表已经收敛到一个确定性的最优策略。如果步数始终在波动优先怀疑时间惩罚与终点奖励的比例关系终点奖励要大于时间惩罚乘以路径长度的上限否则智能体可能认为永远不走到终点反而是高回报策略——这在训练曲线上表现为总奖励迟迟为负。5.2 改进技巧Q 表初始化、ε 衰减曲线与障碍物代价的变化三个可以立刻试的改进方向Q 表初始化。初始值全 0 会让智能体的第一次成功探索产生较大幅度的更新后续学习容易受早期随机路径影响。一个常见做法是把不可通行状态的 Q 值初始化为一个大负数如-100确保智能体从第一轮开始就会避开撞墙可通行状态初始化为0。这个改造只需要一行代码Q zeros(n_states, n_actions); for s 1:n_states [r, c] ind2sub([rows, cols], s); if maze(r, c) 1 Q(s, :) -100; end endε 衰减改成多段式。固定epsilon_decay在 500 episode 内的衰减曲线是平滑的但不同训练阶段对探索的需求不同。我的习惯是分三段前 30% 训练保持高探索ε 0.9 ~ 1中间 40% 线性降到 0.2后 30% 从 0.2 衰减到 0.01。这个方案比指数衰减更好控制训练节奏代价是需要多写几行判断。增加障碍物代价惩罚。如果迷宫里有些区域虽然可通行但明显是死胡同通常与终点相距很远可以给这些格子加一个额外的负奖励初始 Q 值比如-5。这相当于把先验知识注入 Q 表加速训练收敛。但注意这只是初始化技巧不能替代奖励函数的设计——如果羊肠小道也能到达终点且路径更短强加负值反而可能干扰最优策略的发现。5.3 二维迷宫向更复杂场景的泛化方法二维网格迷宫能跑通后往三个方向扩展是常见的实践路径带动态障碍物环境转移函数改为运行时动态计算例如某堵墙每隔一段时间打开或关闭奖励函数增加事件驱动逻辑。Q-Learning 在状态空间扩张后把时间维加到状态里仍然可以训练但需要把“障碍物开关状态”编码进状态索引。连续坐标场地无法枚举离散状态时Q 表失效需要换 SARSA 或 DQN。MATLAB 里可以用rlDQNAgent网络用featureInputLayer定义。三维或者多楼层迷宫纯网格法会面临状态空间爆炸20×20×5 的三维迷宫有 2000 个格子乘 6 个动作 12000 个状态Q 表还能承受但训练时间明显变长。这时需要考虑分层方法先在楼层维度用 Q-Learning再在二维平面内规划路径。5.4 调试口诀训练异常时的三步定位法遇到训练不收敛我一般按固定的顺序排查先看奖励函数——用一行脚本打印前 20 个 episode 每步的实际奖励确认终点奖励是否真的被触发有没有因为撞墙判定顺序写错导致永远到不了终点再看探索率——打印当前 ε 值确认是否衰减过快在智能体还没有找到终点的时候 ε 已经低于 0.1这时候后期 Q 表只会小幅更新很难修正错误认知最后看 Q 表分布——用histogram(Q(:))画一下 Q 值的分布如果所有值都在-1和0之间说明智能体几乎没到达过终点奖励信号没有传播开需要把终点奖励调大、时间惩罚调小或者减小迷宫尺寸验证代码正确性。这种“先奖励、再探索、后 Q 表”的顺序能覆盖 90% 以上的训练异常。迷宫路径规划在强化学习里算是难度最低的类型但正是因为它简单才能把 Q 表更新、参数影响和收敛判定这些底层机制看得明明白白——这些经验直接迁移到时序控制、资源调度这些更复杂的 Q-Learning 应用时照样管用。本文还有配套的精品资源点击获取
返回列表