资讯动态

双目标路径规划:用深度强化学习实现风险感知与最短路径的平衡

发布时间:2026/9/10 3:50:07 来源:尧图企业网站定制
简介面向人工智能、计算机、自动化等专业的毕业设计与课程实践这份基于深度强化学习的双目标动态感知路径规划源码融合犯罪风险与路径距离两个优化目标通过智能体对动态环境进行实时感知并生成最优路线可应用于智慧安防、应急救援、智能交通等路径决策场景。包内共36个文件压缩包仅298KB包含29个Python核心脚本、2个Markdown说明文档、1个TXT文本文件、运行日志及许可证文件其中Python代码覆盖模拟环境构建、强化学习模型训练、风险评估与路线生成等模块每一部分都经过运行测试模块划分清晰便于按需查看与二次开发。项目附有README和环境基础说明下载后即可快速理解算法流程同时也可在此基础上修改目标函数或网络结构以适配新的研究课题。该源码作为本科毕业设计完成度较高答辩评审平均分达到96分代码全部测试通过后才上传目前已有207人学习参考对于希望快速搭建深度强化学习路径规划实验的开发者而言是一份不错的动手范例。1. 双目标路径规划为什么不能只算最短路径——深度强化学习入场的三个理由传统 A* 或 Dijkstra 在城市路网里给出的最短路径放在犯罪风险感知场景里几乎不可用。原因很直接距离最短的路线很可能穿过高发案区域用户的安全代价远高于节省的那几分钟。而单纯绕开高风险区的方案又会导致绕行距离陡增用户不愿意接受。这就是双目标动态感知路径规划要解决的核心问题——在路径距离与犯罪风险之间存在非线性的、随时间变化的权衡关系静态权重求和的做法在环境变化后必须重新调参。这类问题用深度强化学习建模的优越性在于智能体通过与仿真环境持续交互能学出一套隐式的权衡策略风险分布变化时不必人工重设权重策略会自适应地调整路径偏好。适合做这项技术复现的人群是已有 Python 和基础 DL 经验、想用强化学习替代传统图搜索做路线决策的算法工程师和研究生。2. 从风险热力到安全语义MDP 建模与奖励函数的分层设计2.1 为什么把路径规划写成马尔可夫决策过程而不是监督学习把路径规划当监督学习做是最常见的误用收集一批最优路径作为标签训练网络模仿。问题在于标签的最优性本身依赖于当时的动态风险分布环境一变标签就过期。MDP 建模则不同它把问题拆成状态、动作、转移概率和奖励四要素智能体通过试错来逼近最优策略不依赖固定标签。这里我给出本仓库algorithm目录下仿真器的状态定义方式。状态编码采用多层栅格通道叠加核心参数如下表参数名取值含义grid_size30栅格地图边长30x30 网格risk_min0.0风险归一化下界risk_max1.0风险归一化上界dist_scale/10距离惩罚系数缩放state_channels5状态张量通道数状态张量是 5 个 HxW 通道的拼接当前点热力、邻近区域风险均值、历史轨迹热力叠加、目标点方向场、障碍物掩码。动作空间是 8 邻域移动方向加上原地等待一共 9 个离散动作。2.2 双目标权衡一定不能直接相加风险与距离直接加权求和作为奖励比如R w1*risk w2*dist会让训练对 w1、w2 的取值极其敏感。不同城市的路网密度、风险分布差异很大一组权重迁移到另一个场景后策略会崩溃。本仓库的做法是分开惩罚再通过风险阈值做不等式约束。def compute_reward(state, action, next_state, config): # 距离惩罚当前步的移动开销diag_weight 用于对角线移动 step_cost 1.0 if action in [0, 2, 5, 7] else config.diag_weight # 风险惩罚进入 next_state 所在格子的归一化风险值 risk_penalty next_state.risk_map[next_state.x, next_state.y] # 越界或碰撞障碍直接给出大的负奖励 if next_state.is_collision: return -config.collision_penalty, True # 到达目标正奖励并截断 if (next_state.x, next_state.y) config.goal: return config.goal_reward config.time_penalty * next_state.t, True # 风险硬约束超过风险上限则额外惩罚 if risk_penalty config.risk_tolerance: return -(step_cost config.risk_beyond_tol), False return -(step_cost 0.5 * risk_penalty), False代码说明距离惩罚是基础代价风险惩罚作为叠加项risk_tolerance是风险容忍上限。超过该上限时额外惩罚risk_beyond_tol从而把风险约束融入奖励而不是靠权重硬压。动作编号上0、2、5、7 对应上下左右四方向其余为斜向所以diag_weight单独配置。time_penalty的作用是防止智能体在栅格里绕圈。2.3 奖励塑造中间的每一步都要有反馈稀疏奖励在地图尺寸超过 20 时几乎无法收敛智能体到达目标前拿到的一律是 0 或 -1 的话学习效率极低。本仓库的做法是引入势能函数奖励用当前点到目标点的欧氏距离变化提供中间反馈def potential_shaping(state, next_state, config): # 当前势能到目标点的欧氏距离负值 phi_cur -np.hypot(state.x - config.goal[0], state.y - config.goal[1]) phi_next -np.hypot(next_state.x - config.goal[0], next_state.y - config.goal[1]) return config.shaping_gamma * phi_next - phi_curshaping_gamma一般取 0.9。势能塑造的原理是每走一步如果离目标更近了就额外给一个小正奖励反之给负。这一步让智能体在早期训练阶段也能学到一个大致朝目标走的方向感然后才谈得上绕开高风险区域。这里有个需要注意的点势能函数不能设计得和最优策略的目标函数冲突否则智能体会在原地反复蹭势能奖励解决方案是把势能幅度控制在步长惩罚的 1/3 之内。3. 仓库实现拆解A-DYNA 的算法流程与关键代码走读3.1 仓库结构映射simulator、algorithm、tests 各自承担什么从项目文件结构看代码分四个核心区域simulator负责栅格地图、风险分布生成和智能体状态转移algorithm目录存放强化学习主逻辑包含网络定义、经验回收池、训练循环tests是单元测试与收敛性验证脚本testtest和demo类脚本用于快速查看训练效果。README.md是入口文档描述了依赖环境和启动方式。这个组织方式把仿真与学习解耦换真实地图数据时只需要改 simulator 的输入接口。3.2 DQN 变体实现经验池采样与目标网络更新节奏主算法基于 Double DQN。相比原生 DQNDouble DQN 把动作选择和动作评估拆到两个网络上从而缓解 Q 值过估计。这里的网络结构是三层卷积加一层全连接输入是 5 通道状态输出是 9 个动作的 Q 值。经验池容量默认 50000每次采样 batch 为 64。目标网络同步周期是 1000 步这个值需要根据地图大小调整地图越大步数越多同步周期越短。def update(self, batch_size64): if len(self.replay_buffer) batch_size: return batch random.sample(self.replay_buffer, batch_size) states torch.FloatTensor([t[0] for t in batch]) actions torch.LongTensor([t[1] for t in batch]) rewards torch.FloatTensor([t[2] for t in batch]) next_states torch.FloatTensor([t[3] for t in batch]) dones torch.BoolTensor([t[4] for t in batch]) q_values self.policy_net(states).gather(1, actions.unsqueeze(1)) with torch.no_grad(): next_actions self.policy_net(next_states).argmax(dim1, keepdimTrue) next_q self.target_net(next_states).gather(1, next_actions).squeeze(1) target_q rewards self.gamma * next_q * (~dones) loss F.mse_loss(q_values.squeeze(1), target_q) self.optimizer.zero_grad() loss.backward() self.optimizer.step()代码逻辑说明next_actions用 policy_net 选next_q用 target_net 算值正是 Double DQN 的「动作选择与价值评估分离」。dones的作用是终止状态下不再累加未来回报。训练阶段这个update函数每隔 step 调用一次调用的频率就是每步训一次。GPU 显存不足时可以把 batch_size 降到 32但代价是收敛方差变大。3.3 仿真器里风险分布如何生成与更新动态感知体现在simulator的 risk_map 更新机制上。风险分布不是训练前生成一次就固定住而是按 episodes 进行小范围扰动。每个 episode 开始时风险热力会沿 2D 高斯核做随机漂移def perturb_risk_map(self, sigma0.3): noise np.random.normal(0, sigma, self.risk_map.shape) updated self.risk_map noise self.risk_map np.clip(updated, 0.0, 1.0) # 与障碍物掩码相乘保证障碍物格子的风险值恒为 0 self.risk_map * self.obstacle_mask扰动幅度sigma控制环境变化强度0.3 表示单步风险值会变化约正负 0.3。这一设计迫使策略不能死记硬背风险地图而要学会利用周边区域的风险相对关系做推断。如果你把sigma调到 0.5 以上训练难度会显著增加需要相应增加探索率。4. 训练流程与收敛性把控探索率退化、奖励记录与模型持久化4.1 探索率退化的正确节奏DQN 类算法经典的 ε-greedy 探索在路径规划任务里有特殊处理。城市路网中步骤数可达数百步探索率衰减过快智能体会卡在局部最优衰减过慢训练时间拉长。下面这段来自algorithm/train.py的探索策略值得直接参考def epsilon_schedule(episode, total_episodes): 线性退火 下限截断。前40%的episode快速探索 后60%逐步收敛到稳定策略。 if episode total_episodes * 0.4: return 0.9 - episode * 0.5 / (total_episodes * 0.4) return 0.4 * pow(0.995, episode - total_episodes * 0.4)第一段从 0.9 快速降到 0.4让智能体在比较早期就看到足够多的风险分布模式第二段指数下降训练中后期逐步减少随机动作策略趋于确定。0.995的衰减系数适用于 1000 个 episode 以上的训练。如果训练时间紧张、总 episode 只有 300衰减系数应调为 0.98。判断探索率是否合理的方法是观察目标达成率——如果 30 个 episode 内达成率一直为 0多半是探索率太低。4.2 奖励曲线怎么读分开记录距离与风险两个指标训练时只盯着总奖励曲线很容易被波动性误导。保险的做法是把距离代价和风险代价分开记录训练结束后分别画两条曲线python train.py --episodes 1500 --log_dir ./logs # 训练结束后查看日志目录下生成的 reward.csv、risk_cost.csv、dist_cost.csvrisk_cost.csv中每条记录是该 episode 累计的风险惩罚值。如果该值经过 500 个 episode 后仍在高位震荡要么是risk_tolerance设得太严例如 0.2 以下智能体无法同时满足安全与到达目标要么是探索率衰减过快策略没有充分尝试绕行路线。dist_cost.csv增长而risk_cost下降说明策略在主动绕行这是预期行为不是异常。4.3 断点续训与模型持久化检查点该存哪些字段每次训练间隔固定 episode 数保存检查点保存对象除了网络权重还要把优化器状态、经验池抽样索引、当前 epsilon 和 episode 计数一起写盘torch.save({ policy: self.policy_net.state_dict(), target: self.target_net.state_dict(), optimizer: self.optimizer.state_dict(), epsilon: self.epsilon, episode: ep, replay_buffer: list(self.replay_buffer), }, fcheckpoints/ddqn_ep{ep}.pth)如果只保存网络权重恢复训练时 epsilon 和优化器状态会丢失。epsilon 重置过高会让策略脱离原有学习节律优化器 Adam 状态丢失则会阶段性地增大 loss 波动。经验池序列化是一个低成本保险即使恢复后想从不同分布继续采样也有数据支撑。5. 场景迁移与验证技巧新地图上评估策略时要关注的三类指标5.1 从训练环境切换的真实地图输入接口如何对齐把仿真器换成真实城市路网数据时常见做法是保留算法模块不动只替换 simulator 的load_map()方法。state_channels 的 5 通道结构依然可用但真实路网往往是稀疏图而非栅格地图一般先做栅格化把道路交点映射到网格坐标非道路区域视为障碍物。风险数据用地块级别的事故统计填充到网格单元。这里有一个关键坑——坐标对齐。真实经纬度转网格坐标时取整误差会导致路径穿墙需要在load_map()中做碰撞检测和路径平滑后处理。评估一个训练好的策略在新地图上的表现不要只跑一两次看目标达成率。一次性结果有随机性需要统计分布指标定义合格线到达率100 次测试中成功到达目标的次数百分比≥ 95%平均风险代价路径经过网格的风险值累加均值≤ 训练集风险均值的 1.2 倍平均绕行率实际路径长度与最短路径长度之比减 1≤ 30%绕行率超过 30% 时策略可能过度规避风险需要调低risk_tolerance或减小风险惩罚系数 0.5。需要留意的是新地图的风险分布与训练集差异过大时前面的指标都可能不达标这时不要急于调参与微调先确认状态编码中的风险通道归一化方式是否与新数据一致。5.2 策略可视化把决策路径叠加到风险热力图上调参环节最直接的工具是把智能体决策路径覆盖到风险热力图上逐帧观察它在哪里选择绕行、在哪里选择直穿。下面的脚本可以在测试模式下渲染一张带路径的风险图def render_episode(env, policy_net): state env.reset() path [] total_risk, total_dist 0.0, 0.0 for step in range(env.max_steps): action policy_net.act(state, exploreFalse) next_state, reward, done, info env.step(action) path.append((next_state.x, next_state.y)) total_risk next_state.risk_map[next_state.x, next_state.y] total_dist 1.0 if action not in [0, 2, 5, 7] else env.diag_weight if done: break state next_state # 把路径叠加到 risk_map 上高风险区域显示为深色背景 plt.imshow(env.risk_map, cmapYlOrRd) plt.plot([p[1] for p in path], [p[0] for p in path], b-, linewidth2) plt.scatter([env.goal[1]], [env.goal[0]], cgreen, s120, marker*) plt.axis(off) plt.savefig(fpath_ep_{env.episode}.png, dpi150)逐帧看路径图能定位两类问题穿透障碍物、在开阔区域反复绕圈。前者来自动作采样越界说明 collision_penalty 不够强后者说明距离惩罚权重过低。修好这两类问题后再回到指标统计。5.3 从仿真到落地路径规划 API 化时需要保留的双目标接口最后如果要把训练好的决策网络做成服务网络输出是 9 个动作的 Q 值不是路径本身。要得到完整路径需要从起点一路执行 argmax 动作直到终点中间把轨迹收集起来。部署时不要丢掉风险热力层的更新接口——本仓库的perturb_risk_map对应真实场景中的实时风险数据流接入新的风险事件时只需更新风险热力图的对应网格策略天然适应新输入。这个设计是本项目作为双目标动态感知方案最值得保留的部分迁移到无人配送、安防巡逻等场景同样适用。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价