资讯动态

强化学习三大算法DQN/PPO/SAC手写实现与调试指南

发布时间:2026/10/14 15:50:34 来源:尧图企业网站定制
简介本资源是一套面向Python开发者与人工智能学习者的强化学习实践教程聚焦深度强化学习算法的代码实现与原理说明适用于高校学生、算法工程师及希望从理论迈向工程落地的进阶学习者。压缩包共384个文件主体为105个Python源码含DQN、A3C等主流算法实现、65个PyTorch模型文件.pt、34个说明文档.txt/.md以及20个训练过程可视化图表.png另有TensorBoard日志文件events.out.tfevents.*体现完整实验轨迹整体大小86.26MB。目前已有193人学习下载反映出较强的技术实践需求。读者可直接复现经典DRL算法在Gym环境中的训练流程获取结构清晰的项目组织含环境封装、策略网络定义、经验回放、评估脚本等模块并结合配套文档理解代码设计逻辑与关键超参调优思路是打通强化学习“概念—代码—调试—分析”闭环的高实用性入门到进阶资源。1. 强化学习代码实现以及文档说明不是调包跑通就完事而是把 DQN、PPO、SAC 的核心逻辑拆进每一行可调试的 Python 脚本里你是不是也试过pip install stable-baselines3跑通 CartPole 示例一换环境就 reward 不收敛改 learning_rate调 batch_sizereward 曲线还是像心电图——忽高忽低最后 flatline这不是你手气差是强化学习黑匣子太深网络结构、目标网络更新时机、GAE λ 值、entropy 系数……任何一个参数卡在临界点整个训练就静默崩塌。这份「强化学习代码实现以及文档说明」资源就是为这种场景而生的它不提供封装好的.train()接口而是用纯 PyTorch 从零手写 DQN含 Double Dueling、PPO带 GAE 和 clip ratio 动态裁剪、SAC含自动 temperature tuning每份代码都配对应 PDF 文档逐函数标注数学公式来源比如compute_gae()旁直接印着 Schulman 2015 公式 (11)、变量物理意义log_alpha不是随便起名是 entropy 正则项的拉格朗日乘子、梯度回传路径哪一行触发.backward()哪一层被 freeze。适合两类人新手想真正看懂 policy gradient 怎么从 loss 反推 action 分布熟手要复现论文结果、插拔模块做消融实验、或给工业级控制任务加 custom reward shaping。它不是教学视频的字幕稿是能直接git clone python train_dqn.py --env LunarLander-v2启动、打断点、单步跳进target_net.load_state_dict(policy_net.state_dict())看权重拷贝时刻的实操包。2. DQN 实现深度解析从经验回放到双网络软更新为什么 target network 更新频率必须是整数倍 stepDQN 是强化学习落地最稳的起点但它的“稳”全靠几个反直觉设计撑着经验回放打破时序相关性、双网络解耦动作选择与价值评估、目标网络延迟更新抑制震荡。这份资源里的 DQN 实现没用任何高级 trick只用最基础的 PyTorch 模块但把每个设计点都暴露成可调参数——这意味着你能亲手验证“为什么 target update interval 设为 1000 就比 100 更稳”而不是背结论。2.1 经验回放缓冲区不是越大越好关键在采样偏差校正标准 DQN 用collections.deque实现 FIFO 缓冲区但这里采用带优先级的经验回放Prioritized Experience Replay, PER变体核心是SumTree数据结构。它不只存(state, action, reward, next_state, done)还动态维护每个 transition 的 TD error 权重# replay_buffer.py class PrioritizedReplayBuffer: def __init__(self, capacity, alpha0.6): self.capacity capacity self.alpha alpha # 决定 prioritization 强度0uniform, 1full prioritization self.tree SumTree(capacity) self.beta 0.4 # 重要性采样系数随训练逐步增到 1.0 def add(self, state, action, reward, next_state, done): # 初始 priority 设为 max确保新数据必被采样 max_prio self.tree.max_priority() self.tree.add(max_prio, (state, action, reward, next_state, done)) def sample(self, batch_size): segment self.tree.total_priority() / batch_size batch [] indices [] priorities [] for i in range(batch_size): a segment * i b segment * (i 1) s random.uniform(a, b) idx, p, data self.tree.get(s) batch.append(data) indices.append(idx) priorities.append(p) # 计算 importance sampling weights probs np.array(priorities) / self.tree.total_priority() weights (len(self) * probs) ** (-self.beta) weights weights / weights.max() # normalize to [0,1] return batch, indices, weights参数说明alpha0.6是 PER 原论文推荐值过大会导致高频 error 样本垄断训练过小退化为均匀采样beta从 0.4 线性增到 1.0初期降低 bias后期完全校正 sampling bias。weights用于 loss 加权loss (td_error * weights).mean()。这步不能省——否则 high-priority 样本会主导梯度policy 过早坍缩。2.2 双网络架构target network 不是“备份”而是稳定训练的刹车片DQN 最易被忽略的细节是 target network 的更新策略。很多教程写if step % 1000 0: target_net.load_state_dict(policy_net.state_dict())但这里实现更精细支持 hard update全量拷贝和 soft update指数移动平均两种模式并通过tau参数控制平滑度# dqn_agent.py def soft_update_target_network(self, tau0.005): Target network parameters slowly track policy network for target_param, local_param in zip( self.target_net.parameters(), self.policy_net.parameters() ): target_param.data.copy_( tau * local_param.data (1.0 - tau) * target_param.data ) def hard_update_target_network(self, update_interval1000): Full copy every N steps if self.steps_done % update_interval 0: self.target_net.load_state_dict(self.policy_net.state_dict())为什么必须是整数倍 step因为steps_done是全局计数器hard update 需要严格对齐训练节奏。若设为update_interval999.5取整后变成 999 或 1000会导致 target 更新时间抖动TD error 计算基准漂移reward 曲线出现周期性震荡。soft update 虽无此限制但tau0.005对应约 200 步等效延迟e-folding time与 hard update 的 1000 步形成对比实验组——这是资源文档里明确要求你做的消融项。2.3 Loss 函数TD error 不是简单(Q_target - Q_pred)^2而是带 double-Q 的裁剪标准 DQN 的 overestimation 问题在这里用 Double DQN 解决用 policy net 选动作用 target net 评价值避免同一网络既选又评带来的乐观偏差# dqn_trainer.py def compute_td_loss(self, batch): states, actions, rewards, next_states, dones zip(*batch) states torch.stack(states) actions torch.stack(actions) rewards torch.stack(rewards) next_states torch.stack(next_states) dones torch.stack(dones) # Current Q values: Q(s,a) from policy net current_q_values self.policy_net(states).gather(1, actions.unsqueeze(1)) # Double DQN: use policy net to select next action, target net to evaluate next_actions self.policy_net(next_states).max(1)[1].unsqueeze(1) # argmax next_q_values self.target_net(next_states).gather(1, next_actions).squeeze(1) # Compute expected Q values expected_q_values rewards (self.gamma * next_q_values * (1 - dones)) # Huber loss for robustness to outliers loss F.smooth_l1_loss(current_q_values.squeeze(), expected_q_values) return loss关键点next_actions来自self.policy_net实时策略next_q_values来自self.target_net冻结评估二者分离。F.smooth_l1_loss在误差大时转为 L1防止单个 outlier 样本如 episode 结束的 high reward炸掉梯度。文档中特别强调若把next_actions改成self.target_net(next_states).max(1)[1]就退化为原始 DQNoverestimation 会上升 12–18%在 LunarLander 上表现为 landing reward 波动加大。3. PPO 实现精讲clip ratio、GAE λ、entropy bonus 三者如何协同防止 policy collapsePPO 是当前最主流的 on-policy 算法但它的“好用”背后是三个参数的精密咬合clip_epsilon控制 policy 更新步长gae_lambda平衡 bias-varianceentropy_coef防止过早收敛。这份资源的 PPO 实现把三者全部暴露为命令行参数并在文档中给出每种组合在 HalfCheetah-v2 上的 reward 方差热力图——不是告诉你“该设多少”而是让你看清“设错时系统怎么崩溃”。3.1 PPO Clip Loss不是裁剪 gradient而是裁剪 ratio让 policy update 可预测PPO 的核心创新是用 surrogate objective 替代原始 policy gradient通过clip(ratio, 1-ε, 1ε)限制每次更新幅度。这里实现严格遵循 Schulman 2017 原论文且支持clip和adaptive kl两种模式# ppo_agent.py def compute_ppo_loss(self, states, actions, old_log_probs, advantages, returns): # Get new log probabilities and values new_log_probs, entropy, values self.actor_critic(states, actions) # Compute probability ratio ratio torch.exp(new_log_probs - old_log_probs.detach()) # Surrogate loss with clipping surr1 ratio * advantages surr2 torch.clamp(ratio, 1.0 - self.clip_epsilon, 1.0 self.clip_epsilon) * advantages policy_loss -torch.min(surr1, surr2).mean() # Value loss (clipped for stability) value_loss F.mse_loss(values, returns) # Entropy bonus (encourage exploration) entropy_loss -self.entropy_coef * entropy.mean() total_loss policy_loss self.vf_coef * value_loss entropy_loss return total_loss, policy_loss, value_loss, entropy_loss参数说明clip_epsilon0.2是默认值对应 ±20% 的 ratio 裁剪vf_coef0.5平衡 value loss 权重entropy_coef0.01初始值训练中线性衰减到 0.001。注意advantages必须用 GAE 计算不能用 raw Monte Carlo returns——否则 variance 太大clip 失效。文档中给出实测当clip_epsilon从 0.2 降到 0.1HalfCheetah 的 forward speed 方差下降 35%但收敛步数增加 2.1 倍升到 0.3 则 reward 崩溃概率达 68%。3.2 GAE 计算λ 不是超参而是 bias-variance 的滑动变阻器Generalized Advantage Estimation (GAE) 是 PPO 稳定的关键。这份实现提供两种 GAE 模式标准版gae_lambda0.95和可学习 λlearnable_lambdaTrue后者将 λ 作为网络参数联合优化# utils/gae.py def compute_gae(next_values, rewards, dones, values, dones_next, gamma0.99, gae_lambda0.95): Compute GAE: δ_t^V r_t γV(s_{t1}) - V(s_t) A_t Σ_k (γλ)^k δ_{tk}^V gae 0 advantages torch.zeros_like(rewards) # Process backwards for t in reversed(range(len(rewards))): # TD error at time t delta rewards[t] gamma * next_values[t] * (1 - dones_next[t]) - values[t] # GAE accumulation: A_t δ_t γλ A_{t1} gae delta gamma * gae_lambda * (1 - dones_next[t]) * gae advantages[t] gae return advantages为什么 λ0.95 是黄金值λ0 对应 pure MChigh variance, zero biasλ1 对应 TD(0)low variance, high bias。0.95 是经验平衡点在 MuJoCo 任务中λ0.9 时 reward 曲线抖动加剧λ0.97 时收敛变慢且易陷入局部最优。文档中附有 λ0.9/0.95/0.99 三组在 Walker2d 上的 rollout length 对比图——λ0.95 组的步长标准差最小证明其探索效率最高。3.3 Entropy 自动调节不是固定系数而是用 dual gradient descent 学习 temperatureSAC 的 entropy tuning 思想被迁移到 PPO 中entropy_coef不再手动设置而是通过 dual optimization 动态调整使实际 entropy 接近目标值target_entropy# ppo_agent.py def adapt_entropy_coef(self, entropy): # Dual loss: maximize entropy while keeping it near target entropy_diff entropy - self.target_entropy self.entropy_coef torch.clamp( self.entropy_coef * torch.exp(self.entropy_lr * entropy_diff), min1e-5, max1.0 )逻辑说明当entropy target_entropy探索不足entropy_diff 0self.entropy_coef指数衰减降低 entropy penalty鼓励探索反之则增大系数抑制随机性。target_entropy -action_dim是常用设定连续动作空间entropy_lr0.01控制调节速度。实测表明在 Ant-v2 上adaptive 版本比 fixed 0.01 版本的 final reward 提升 11.3%且训练失败率从 22% 降至 3%。4. SAC 实现剖析自动 temperature tuning、twin Q networks、target entropy 的物理意义SAC 是 off-policy 中样本效率最高的算法之一但它的三个核心设计常被误读twin Q networks 不是为了 ensemble而是为了解耦 critic 更新中的 overestimationautomatic temperature tuning 不是调参技巧而是将 entropy constraint 转为可微优化问题target entropy 不是 magic number而是动作空间维度的函数。这份资源的 SAC 实现把每个设计都还原为可调试的 PyTorch 操作并在文档中用 3D 图形展示 temperature 如何随训练动态变化。4.1 Twin Q Networks不是两个网络投票而是用 min(Q1,Q2) 抑制 overestimationSAC 的 critic 不是单个 Q 网络而是两个独立初始化的Q1和Q2loss 计算时取二者最小值# sac_agent.py def compute_critic_loss(self, states, actions, rewards, next_states, dones): # Get current Q values current_q1 self.q1_net(states, actions) current_q2 self.q2_net(states, actions) # Get next Q values using target networks with torch.no_grad(): next_actions, next_log_probs self.actor_target.sample(next_states) next_q1 self.q1_target(next_states, next_actions) next_q2 self.q2_target(next_states, next_actions) # Take min to mitigate overestimation next_q torch.min(next_q1, next_q2) - self.alpha * next_log_probs # Bellman backup target_q rewards self.gamma * next_q * (1 - dones) # Critic loss: MSE between current and target q1_loss F.mse_loss(current_q1, target_q) q2_loss F.mse_loss(current_q2, target_q) return q1_loss q2_loss为什么取 min因为单个 Q 网络在稀疏 reward 下易高估未见过状态的价值。两个独立网络的估计存在差异min(Q1,Q2)保守地选择更低估值相当于引入隐式正则。文档中对比实验在 sparse-reward 版本的 FetchReach 中single Q 版本 80% 任务失败twin Q min 版本成功率 92%。注意next_actions必须来自actor_target目标 actor而非当前 actor——否则引入 bias。4.2 Automatic Temperature Tuningα 不是超参而是拉格朗日乘子用 dual loss 优化SAC 的 entropy termα * H(π)中α 是待学习参数。这里实现用 dual gradient descent 更新 α目标是最小化α * (log π - target_entropy)# sac_agent.py def compute_temperature_loss(self, log_pi): # Dual objective: minimize α * (log π - target_entropy) # Equivalent to maximizing entropy while keeping it near target alpha_loss -(self.log_alpha * (log_pi self.target_entropy).detach()).mean() return alpha_loss def update_temperature(self, log_pi): self.alpha_optim.zero_grad() alpha_loss self.compute_temperature_loss(log_pi) alpha_loss.backward() self.alpha_optim.step() # Update alpha value self.alpha self.log_alpha.exp().item()物理意义log_alpha是 entropy constraint 的拉格朗日乘子target_entropy -np.prod(self.action_space.shape)是理论最优熵高斯分布最大熵。当实际log_pi target_entropy策略太确定alpha_loss为正log_alpha增大α 增大entropy penalty 加重迫使 policy 更随机反之则 α 减小。文档中可视化了 α 在训练中的轨迹前 10k 步快速上升至 0.15随后缓慢下降最终稳定在 0.08对应实际 entropy 与 target 的误差 0.02。4.3 Target Network Soft Updateτ0.005 不是随意选而是匹配 critic 更新频率SAC 的 target networksactor_target, q1_target, q2_target全部用 soft update且共享同一 τ# sac_agent.py def soft_update_target_networks(self, tau0.005): for target, source in zip( self.actor_target.parameters(), self.actor.parameters() ): target.data.copy_(tau * source.data (1.0 - tau) * target.data) for target, source in zip( self.q1_target.parameters(), self.q1_net.parameters() ): target.data.copy_(tau * source.data (1.0 - tau) * target.data) for target, source in zip( self.q2_target.parameters(), self.q2_net.parameters() ): target.data.copy_(tau * source.data (1.0 - tau) * target.data)为什么 τ0.005它对应 e-folding time ≈ 200 步1/τ与 critic 的 update frequency每步都更新形成时间尺度分离critic 快速拟合target network 慢速跟踪避免 bootstrapping error 累积。若 τ0.1则 target 更新太快失去稳定性τ0.001 则太慢critic 无法及时获得准确 target。文档中给出 τ0.001/0.005/0.01 三组在 Humanoid-v2 上的 training curves——τ0.005 组的 reward 标准差最小且首次突破 5000 reward 的步数最快。5. 避坑指南强化学习训练中五个血泪教训每个都对应一个真实翻车现场强化学习训练不是写完代码就能跑通而是不断和随机性、数值不稳定、环境 bug 打交道的过程。这份资源的文档里专门有一章记录了作者在复现 12 篇顶会论文过程中踩过的坑每一条都附带现象截图、根本原因分析和可验证的修复命令。以下是其中最典型的五条按发生频率排序5.1 现象reward 曲线在 10k 步后突然归零且不再恢复原因PyTorch 默认使用torch.float32但在某些 GPU如 A100上混合精度训练AMP被意外启用导致 critic 网络输出inf或nan后续log_prob计算崩溃。torch.isnan(loss).any()返回True但训练循环未检查继续 backward权重变为nan。解决在 trainer 主循环中强制插入 nan 检查并禁用 AMP除非显式开启# train_sac.py if torch.isnan(loss).any(): print(fNaN detected at step {step}, resetting optimizer) self.optimizer.zero_grad() # clear corrupted gradients # Re-initialize critic networks self.q1_net.apply(self._init_weights) self.q2_net.apply(self._init_weights) continue提示_init_weights使用torch.nn.init.xavier_uniform_非orthogonal_因后者在 nan 后难以恢复。5.2 现象PPO 在 early training 阶段 reward 持续下降1000 步后才反弹原因advantages计算时未正确处理dones。标准 GAE 要求dones_next[t]表示t1步是否 done但很多实现错误地用了dones[t]导致 episode 结束后的δ_t被错误计算为r_t - V(s_t)而非r_t因为V(s_{t1})0。解决严格按 GAE 公式定义dones_next并在compute_gae中显式处理# utils/gae.py # Ensure dones_next[i] is done flag for state[i1] dones_next torch.cat([dones[1:], torch.tensor([0], dtypetorch.bool)]) # Then in GAE loop: delta rewards[t] gamma * next_values[t] * (1 - dones_next[t]) - values[t]5.3 现象DQN 在 LunarLander 上 reward 卡在 150无法突破 200原因epsilon-greedy的epsilon衰减过快。默认epsilon_decay0.9951000 步后epsilon0.0067agent 过早停止探索困在次优策略。解决改用线性衰减并延长 exploration phase# dqn_agent.py def select_action(self, state): self.steps_done 1 # Linear decay from 1.0 to 0.01 over 50000 steps epsilon max(0.01, 1.0 - self.steps_done / 50000.0) if random.random() epsilon: with torch.no_grad(): return self.policy_net(state).max(1)[1].view(1, 1) else: return torch.tensor([[random.randrange(self.n_actions)]])5.4 现象SAC 的alpha在训练中持续增大最终log_alpha10policy 完全随机原因target_entropy设定错误。对于离散动作空间target_entropy -log(n_actions)但代码中误用target_entropy -n_actions导致 entropy 目标过大α 被迫无限增大以满足约束。解决根据动作空间类型自动计算target_entropy# sac_agent.py if isinstance(self.action_space, Discrete): self.target_entropy -np.log(self.action_space.n) elif isinstance(self.action_space, Box): self.target_entropy -np.prod(self.action_space.shape) else: raise NotImplementedError(Only Discrete and Box supported)5.5 现象多进程训练Ray/Ray Tune时reward 曲线剧烈抖动不同 worker 结果差异巨大原因各 worker 使用相同随机 seed 初始化网络导致所有 agent 学到相似策略经验回放缺乏多样性。off-policy 算法依赖 diverse data同质化数据引发 collapse。解决在每个 worker 初始化时用进程 ID 生成唯一 seed# train_multiprocess.py import os worker_id int(os.environ.get(RAY_WORKER_ID, 0)) seed base_seed worker_id torch.manual_seed(seed) np.random.seed(seed) random.seed(seed)注意base_seed必须是固定值如 42不可用time.time()否则无法复现。6. 验证与调试技巧用 reward decomposition、gradient norm tracking、policy entropy heatmap 三招定位失效环节训练强化学习模型不能只盯着最终 reward。我从某高校实验室接手一个卡在 85% success rate 的抓取任务时发现 90% 的失败发生在“接近物体后突然松开夹爪”——这根本不是 reward 设计问题而是 actor 网络在特定 state 下输出了错误 action。从此我养成了三个必做验证步骤它们不增加训练时间却能在 5 分钟内定位 80% 的失效根源。这份资源的文档里每个算法都附带对应的验证脚本以下是我现在每次 run 实验必走的流程。6.1 Reward Decomposition把总 reward 拆成 spatial、temporal、task-specific 三部分很多 reward 不收敛是因为 reward signal 混淆了多个目标。例如在机械臂抓取中reward distance_reward grasp_reward lift_reward但distance_reward的 scale 是 0.1grasp_reward是 10梯度几乎全被 grasp 主导。这里用RewardDecomposer类实时分解# utils/reward_decomposer.py class RewardDecomposer: def __init__(self, env_name): self.env_name env_name self.decomposition { distance: [], grasp: [], lift: [], total: [] } def step(self, obs, reward, info): if distance_reward in info: self.decomposition[distance].append(info[distance_reward]) if grasp_reward in info: self.decomposition[grasp].append(info[grasp_reward]) if lift_reward in info: self.decomposition[lift].append(info[lift_reward]) self.decomposition[total].append(reward) def plot_decomposition(self, window100): # Plot rolling mean of each component fig, ax plt.subplots(figsize(10,6)) for key in [distance, grasp, lift]: if self.decomposition[key]: y np.convolve(self.decomposition[key], np.ones(window)/window, modevalid) ax.plot(y, labelf{key} (rolling {window})) ax.legend() ax.set_title(Reward Decomposition) plt.savefig(reward_decomp.png) plt.close()操作在env.step()后调用decomposer.step(obs, reward, info)info 字典需由 env 提供各子 reward。运行 10k 步后执行plot_decomposition()若发现grasp曲线已饱和9.5但distance仍在下降-0.2说明问题在接近阶段——立刻去检查distance_reward的计算逻辑而非调整个体网络。6.2 Gradient Norm Tracking监控 critic 和 actor 的 grad_norm识别梯度爆炸/消失强化学习中ciritc 的梯度常比 actor 大 10 倍若不监控ciritc 会先崩溃再拖垮 actor。这里用GradientTracker在每次optimizer.step()前记录# utils/grad_tracker.py class GradientTracker: def __init__(self, model, name): self.model model self.name name self.grad_norms {critic: [], actor: []} def track(self, loss, optimizer): optimizer.zero_grad() loss.backward() # Track grad norm before step total_norm 0 for p in self.model.parameters(): if p.grad is not None: param_norm p.grad.data.norm(2) total_norm param_norm.item() ** 2 total_norm total_norm ** 0.5 self.grad_norms[self.name].append(total_norm) # Optional: clip if too large if total_norm 10.0: torch.nn.utils.clip_grad_norm_(self.model.parameters(), 10.0) optimizer.step()阈值参考正常训练中critic grad_norm 应在 0.5–5.0 区间波动若持续 10.0说明 reward scale 或 loss function 有问题若 0.01说明 critic 已饱和需检查target_q是否恒定。actor grad_norm 通常为 0.1–1.0若长期 0.05大概率是 entropy coefficient 过大或 reward signal 太弱。6.3 Policy Entropy Heatmap在 state space 关键切片上可视化 policy 输出的 entropy 分布policy entropy 不是 scalar而是 state 的函数。高 entropy 区域代表 agent 不确定应重点检查 reward 设计或 state representation。这里用EntropyHeatmap在 2D state slice 上采样# utils/entropy_heatmap.py def plot_policy_entropy_heatmap(agent, state_bounds, resolution50): x_min, x_max, y_min, y_max state_bounds x np.linspace(x_min, x_max, resolution) y np.linspace(y_min, y_max, resolution) X, Y np.meshgrid(x, y) entropies np.zeros_like(X) for i in range(resolution): for j in range(resolution): # Construct state vector (assume first 2 dims are x,y) state np.zeros(agent.state_dim) state[0] X[i,j] state[1] Y[i,j] state torch.tensor(state, dtypetorch.float32).unsqueeze(0) with torch.no_grad(): _, log_probs agent.actor.sample(state) entropy -log_probs.exp() * log_probs entropies[i,j] entropy.sum().item() plt.figure(figsize(8,6)) plt.contourf(X, Y, entropies, levels20, cmapviridis) plt.colorbar(labelPolicy Entropy) plt.title(Policy Entropy Heatmap) plt.xlabel(State Dim 0) plt.ylabel(State Dim 1) plt.savefig(entropy_heatmap.png) plt.close()使用场景在 LunarLander 中将 state 的x_pos和y_pos作为切片维度运行此脚本。若发现 landing zonex≈0, y≈0entropy 极低0.1但周围区域 entropy 1.5说明 policy 在关键区域过度自信——此时应检查 reward 是否在 landing 时给予过高 bonus导致 policy 忽略姿态控制。从那以后我每次设计 reward都强制走一遍 entropy heatmap哪怕只花 2 分钟。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑