
简介本资源面向通信、边缘计算与强化学习方向的学生及研究人员提供一套基于无人机辅助移动边缘计算的计算卸载优化完整实现采用深度确定性策略梯度DDPG方法适合作为毕业设计、课程大作业或算法复现的参考项目。压缩包共17个文件以16个Python源码和1份Markdown说明为主整体约44KB代码含详细注释新手也能理解。内容涵盖UAV_env.py环境建模、ddpg_algo.py算法实现、state_normalization.py状态归一化并附带Actor-Critic、DQN、Edge_only、Local_only等对比方案便于横向比较不同卸载策略的性能差异。目前已有130人学习下载。读者可借此掌握无人机轨迹与计算卸载联合优化的建模思路、DDPG训练流程及基线对照实验设计快速搭建可运行实验环境并用于论文或答辩展示。1. 无人机辅助边缘计算卸载这套 DDPG 源码到底能跑出什么如果你正在做无人机辅助移动边缘计算方向的计算卸载优化大概率会遇到一个尴尬局面论文里的 DDPG 公式推导看得懂但真要自己从零搭一个能收敛的仿真环境状态空间、动作空间、奖励函数三者怎么对齐往往卡上一两周。这套源码解决的正是这个断层——它把 UAV 辅助 MEC 的计算卸载建模成一个连续动作控制问题用 DDPG 训练卸载决策同时附带 DQN、Local_only、Edge_only 三组基线做对照。目录结构里UAV_env.py是环境核心ddpg_algo.py是算法主体state_normalization.py负责状态归一化另外还拆出了DDPG_without_state_normalization和DDPG_without_behavior_noise两个消融版本。适合谁做毕业设计、课程大作业、研究生阶段想快速复现对比实验的人。新手能顺着 README 跑通熟手能直接改奖励函数和信道模型做自己的实验。2. 环境建模与 DDPG 选型为什么连续动作比离散卸载更贴合 UAV 场景2.1 计算卸载为什么落到 DDPG 上先把这个问题的本质说清楚。移动边缘计算里的计算卸载核心决策是一个计算任务是放在本地设备算还是卸载到边缘服务器算卸载的话分配多少带宽、多少算力。传统做法把卸载比例离散成若干档用 DQN 去选。但 UAV 辅助场景有个特殊性——无人机的位置、发射功率、任务拆分比例本质上都是连续量硬离散化会带来两个问题一是动作空间随精度指数膨胀二是相邻动作之间的物理差异被抹平策略学出来抖动大。DDPG 的价值在于它直接输出连续动作。Actor 网络输出一个确定性的动作向量Critic 网络评估这个动作的 Q 值配合经验回放和目标网络软更新来稳定训练。放到这套源码里Actor 输出的动作对应卸载比例和资源分配系数Critic 根据当前 UAV 状态和动作给出价值估计。选它而不是 PPO 或 SAC一个现实原因是这套代码的定位是教学和毕设复现DDPG 结构清晰、参数量少、调参路径短跑在普通笔记本上也能在合理时间内看到收敛曲线。2.2 环境文件 UAV_env.py 的状态、动作、奖励三要素打开UAV_env.py你要盯住三个东西状态向量怎么拼、动作向量怎么定义、奖励函数怎么算。常见做法是状态里放任务数据量、本地计算能力、UAV 到地面设备的信道增益、UAV 剩余能量、当前时隙位置。动作一般是二维或三维连续向量比如卸载比例 α∈[0,1] 和 UAV 发射功率分配。奖励通常是负的时延和能耗加权和训练目标就是让累计奖励最大也就是时延能耗最小。下面这段是我按这套源码结构还原的环境核心逻辑帮你理解每个量的物理含义import numpy as np class UAVEnv: def __init__(self): # 状态维度任务量、本地算力、信道增益、剩余能量、位置 self.state_dim 5 # 动作维度卸载比例 功率分配系数 self.action_dim 2 self.action_low np.array([0.0, 0.0]) self.action_high np.array([1.0, 1.0]) def reset(self): # 每个 episode 重置 UAV 位置、能量和任务队列 self.uav_energy 1.0 self.position np.random.uniform(0, 500, size2) state np.array([ np.random.uniform(1e6, 5e6), # 任务数据量 bit np.random.uniform(0.5e9, 2e9), # 本地算力 Hz np.random.uniform(1e-6, 1e-4), # 信道增益 self.uav_energy, self.position[0] ]) return state def step(self, action): offload_ratio np.clip(action[0], 0, 1) power_coef np.clip(action[1], 0, 1) # 本地计算时延 卸载传输时延 边缘计算时延 local_delay (1 - offload_ratio) * self.task_size / self.local_freq trans_delay offload_ratio * self.task_size / (self.bandwidth * np.log2(1 power_coef * self.channel_gain)) edge_delay offload_ratio * self.task_size / self.edge_freq total_delay local_delay trans_delay edge_delay energy power_coef * trans_delay 0.1 * local_delay reward -(0.6 * total_delay 0.4 * energy) # 时延能耗加权 self.uav_energy - energy done self.uav_energy 0 next_state self._get_next_state() return next_state, reward, done, {}逻辑说明reset()每次生成一个新的任务和信道条件保证训练样本多样。step()里把动作拆成卸载比例和功率系数分别算本地、传输、边缘三段时延再按权重合成奖励。参数说明奖励里的 0.6 和 0.4 是时延与能耗的权衡系数改这个值会直接改变策略偏好——调大时延权重策略会更激进地卸载调大能耗权重策略会倾向本地计算省电。action_low和action_high定义了动作边界DDPG 输出经过 tanh 后要映射到这个区间这一步在ddpg_algo.py里做。2.3 基线对照DQN、Local_only、Edge_only 各自验证什么这套源码把基线拆得很清楚这是它比很多单文件代码强的地方。Local_only是全部本地计算代表不卸载的下界Edge_only是全部卸载代表无脑卸载的上界参照DQN是把动作离散化后的强化学习对照。你跑实验时把 DDPG 的收敛曲线和这三条放一起就能说明连续动作策略相对离散策略和两种极端策略的优势。DDPG_without_state_normalization和DDPG_without_behavior_noise是消融实验分别验证状态归一化和行为噪声对收敛的影响——这两个消融点恰好是 DDPG 训练最容易翻车的地方后面避坑章节会细说。3. 从零跑通训练环境配置、超参设置与收敛判断3.1 依赖安装与目录结构确认拿到压缩包解压后先确认目录层级。根目录下有5-main里面按算法分了DDPG、DQN、Local_only、Edge_only四个子目录每个子目录里都有独立的UAV_env.py和对应的算法文件。这种结构的好处是每个实验互不干扰坏处是环境文件有重复改环境时要同步改多个副本这点后面避坑会提。依赖方面这套代码是纯 Python 科学计算栈常见做法是建一个虚拟环境再装python -m venv uav_mec_env source uav_mec_env/bin/activate # Windows 用 uav_mec_env\Scripts\activate pip install numpy torch matplotlib逻辑说明venv隔离依赖避免和你机器上其他项目的 torch 版本打架。numpy负责数值运算torch是 DDPG 的网络后端matplotlib用来画收敛曲线。参数说明torch 装 CPU 版就够这套网络规模很小两层全连接各 256 个神经元CPU 训练一个 episode 通常在秒级。如果你要跑几百个 episode 的完整对比GPU 能省时间但不是必须。3.2 DDPG 超参怎么设Actor/Critic 学习率与软更新系数ddpg_algo.py里几个超参直接决定能不能收敛。我按这套代码的常见配置列一下并说清每个值改了会怎样超参典型值作用调大后果调小后果Actor 学习率1e-4策略网络更新步长策略震荡不收敛学习过慢Critic 学习率1e-3价值网络更新步长Q 值发散价值估计滞后软更新系数 tau0.005目标网络跟随速度目标不稳定跟随太慢回放缓冲区1e5经验存储容量占内存样本相关性高批大小64每次采样数训练慢梯度噪声大行为噪声 sigma0.2探索强度动作抖动探索不足Critic 学习率比 Actor 大一个量级是常规操作因为 Critic 要先学准价值Actor 才有靠谱的梯度方向。软更新系数 tau 用 0.005 意味着目标网络每步只挪一点点这是 DDPG 稳定的关键很多人图快把 tau 调到 0.05结果就是训练曲线像心电图。3.3 训练循环与收敛曲线判读主训练循环一般长这样我按源码结构还原import torch import numpy as np from ddpg_algo import DDPG from UAV_env import UAVEnv env UAVEnv() agent DDPG(state_dimenv.state_dim, action_dimenv.action_dim) episodes 500 reward_history [] for ep in range(episodes): state env.reset() ep_reward 0 for t in range(200): # 每个 episode 最多 200 步 action agent.select_action(state) next_state, reward, done, _ env.step(action) agent.store_transition(state, action, reward, next_state, done) agent.update() # 从回放池采样更新 Actor 和 Critic state next_state ep_reward reward if done: break reward_history.append(ep_reward) if ep % 50 0: print(fEpisode {ep}, Reward: {ep_reward:.2f})逻辑说明每个 episode 重置环境内层循环走最多 200 步每步选动作、存经验、更新网络。agent.update()内部做的是从回放池随机采样一个 batch算 Critic 损失、Actor 策略梯度再软更新目标网络。参数说明episodes500是经验值这套环境一般 300 到 500 个 episode 能看到曲线走平t上限 200 是防止 UAV 能量耗尽前无限循环。判读收敛看reward_history健康的曲线是前期快速上升、中期小幅震荡、后期趋于平稳。如果 500 个 episode 还在大幅震荡先查状态归一化和行为噪声别急着加网络层数。4. 避坑与排查状态归一化、行为噪声和能量约束的五个血泪坑4.1 现象奖励曲线剧烈震荡不收敛 → 原因状态量纲差异过大 → 解决启用 state_normalization这是 DDPG 在这类环境里最常见的翻车点。状态向量里任务量是 1e6 量级信道增益是 1e-6 量级差了 12 个数量级。神经网络对输入尺度极其敏感量纲不统一会让 Critic 的 Q 值估计完全失准。源码里专门给了state_normalization.py和DDPG_without_state_normalization做对照就是在告诉你这件事。解决方式是在状态送入网络前做标准化常见做法是维护一个运行均值和方差或者直接用固定范围归一化到 [0,1]。如果你自己改环境加了新状态量记得同步更新归一化范围。4.2 现象策略过早收敛到全卸载或全本地 → 原因行为噪声衰减太快 → 解决调 sigma 和噪声衰减策略DDPG 是确定性策略探索全靠加在动作上的行为噪声。如果噪声 sigma 一开始就设得很小或者衰减太快Agent 很快就不再探索直接收敛到某个局部最优——典型表现就是策略一直输出卸载比例接近 0 或接近 1。源码里DDPG_without_behavior_noise就是去掉噪声的消融版你可以对比看它是不是卡在极端策略上。解决方式是 sigma 从 0.2 起步按 episode 缓慢衰减别用指数衰减一步到位。4.3 现象训练到一半 UAV 能量突然耗尽 → 原因奖励函数没约束能耗 → 解决在奖励里加能量惩罚项UAV 的能量是硬约束但如果你奖励函数只算时延Agent 会为了降时延疯狂加大发射功率几个 episode 就把能量烧光之后所有动作都无效训练直接崩。解决是在奖励里显式加能量惩罚或者把剩余能量作为 done 条件提前终止。这套源码的step()里self.uav_energy - energy和done self.uav_energy 0就是干这个的。注意惩罚系数别设太大否则 Agent 会躺平什么都不做。4.4 现象改了 UAV_env.py 但训练结果没变 → 原因多个子目录各有一份环境副本 → 解决确认改的是当前运行目录下的文件前面提过DDPG、DQN、Local_only、Edge_only四个目录各有一份UAV_env.py。你改了 DDPG 目录下的环境但跑的是 DQN 目录的脚本结果当然不变。这个坑不涉及算法纯粹是目录结构导致的但新手很容易在这里耗半天。养成习惯改环境前先确认当前工作目录或者干脆把环境文件抽成公共模块统一引用。4.5 现象Critic 损失突然变成 NaN → 原因Q 值目标发散 → 解决检查奖励尺度并加梯度裁剪DDPG 的 Critic 用 TD 误差更新如果奖励数值太大Q 值会指数级放大直到溢出。这套环境里时延和能耗的量级如果不做缩放奖励可能到几百上千。解决方式是把奖励缩放到合理范围比如除以一个基准值或者在优化器里加梯度裁剪。常见做法是torch.nn.utils.clip_grad_norm_(critic.parameters(), 1.0)把梯度范数限制住防止单步更新过猛。5. 进阶玩法把消融实验做成对比图顺带验证策略合理性跑通基础训练只是第一步这套源码真正的价值在于它给了你一套完整的实验骨架能直接产出毕设或论文需要的对比图。我一般会做三件事。第一把 DDPG、DQN、Local_only、Edge_only 四条曲线画在同一张图上。横轴 episode纵轴累计奖励或平均时延。这张图能同时说明两件事强化学习策略优于两种极端策略连续动作的 DDPG 优于离散动作的 DQN。画图代码不复杂import matplotlib.pyplot as plt def smooth(data, window10): # 滑动平均去掉训练曲线的毛刺 return np.convolve(data, np.ones(window)/window, modevalid) plt.plot(smooth(ddpg_rewards), labelDDPG) plt.plot(smooth(dqn_rewards), labelDQN) plt.axhline(ylocal_baseline, linestyle--, labelLocal_only) plt.axhline(yedge_baseline, linestyle--, labelEdge_only) plt.xlabel(Episode) plt.ylabel(Cumulative Reward) plt.legend() plt.savefig(comparison.png, dpi300)逻辑说明smooth()做滑动平均因为原始训练曲线抖动大直接画看不清趋势。基线是固定值用水平虚线表示。参数说明window10是平滑窗口太大趋势会被抹平太小起不到平滑作用10 到 20 之间比较合适。dpi300是论文插图的基本要求。第二用两个消融版本验证你的设计选择。把DDPG_without_state_normalization和完整版对比如果完整版收敛更快更稳就证明了状态归一化的必要性把DDPG_without_behavior_noise和完整版对比如果去掉噪声后策略卡在次优就证明了探索机制的价值。这两组对比写进报告里比空谈理论有说服力得多。第三验证策略的物理合理性。训练完之后固定一个测试任务看 Agent 输出的卸载比例随信道增益和任务量怎么变。合理的策略应该是信道好、任务大时多卸载信道差、能量低时多本地计算。如果策略输出和物理直觉完全相反那多半是奖励函数设计有问题而不是算法本身的问题。这一步很多人跳过但它是区分「跑通了」和「跑对了」的关键。从那以后我每次拿到这类强化学习仿真代码都强制先跑一遍消融版本确认每个设计选择都有数据支撑再动手改自己的模型。希望帮到你。本文还有配套的精品资源点击获取