
教程机器学习深度学习【免费下载链接】easy-rl强化学习中文教程蘑菇书在线阅读地址https://datawhalechina.github.io/easy-rl/项目地址https://gitcode.com/gh_mirrors/ea/easy-rl点击查看免费下载本章第7章讲解深度Q网络DQN训练中的一系列进阶技巧双深度Q网络Double DQN、竞争深度Q网络Dueling DQN、优先级经验回放Prioritized Experience Replay, PER、多步方法、噪声网络Noisy Net、分布式Q函数Distributional Q-function以及将它们组合起来的彩虹Rainbow。这些技巧解决DQN在实践中的典型问题——Q值过估计、样本利用效率低、探索方式不合理、奖励不确定性被忽视等且彼此之间没有冲突可以叠加使用。本文以蘑菇书Easy-RL第7章为骨架结合仓库中 notebooks 目录下的可运行实现DoubleDQN.ipynb、DuelingDQN.ipynb、PER_DQN.ipynb、NoisyDQN.ipynb与 第7章实践项目逐项拆解每个技巧的原理、公式、实现要点与调参建议帮助读者真正把进阶DQN跑起来。7.1 双深度Q网络解决Q值被高估的问题7.1.1 为什么Q值总是被高估在实现上Q值往往是被高估的。以 4 个不同的小游戏为例见原文档图 7.1横轴代表迭代轮次红色锯齿状曲线表示Q函数对大量不同状态采样后取平均的 Q 值。由于Q函数取决于策略学习过程中策略越来越强同一状态下期望奖励越来越大因此Q值整体呈上升趋势——但这是深度Q网络预估出来的值。随后用策略实际去玩例如100万次统计真实获得的累积奖励会发现预估出来的值远比真实值大且大很多在每一个游戏中都是如此。原因在于式(7.1)的训练目标本身我们希望左侧与右侧目标越接近越好但目标很容易被设得过高因为计算目标时实际上做的是看哪一个动作 $a$ 可以得到最大的Q值就把它加上去变成目标$$ Q\left(s_{t}, a_{t}\right) \longleftrightarrow r_{t}\max{a} Q\left(s{t1}, a\right) \tag{7.1} $$例如有 4 个动作本来它们得到的Q值与奖励都差不多但网络估计有误差。如图 7.2(a) 所示若第一个动作被高估智能体就会选它用被高估的 Q 值加 $r_t$ 当目标若第四个动作被高估图 7.2(b)就会选第四个。智能体总是会选那个 Q 值被高估的动作所以目标值总是太大。7.1.2 DDQN 的解法动作选择与价值计算解耦在DDQN中选动作的Q函数与计算值的Q函数不是同一个。原DQN穷举所有 $a$ 代入Q函数把Q值最高的 $a$ 对应的Q值加 $r_t$DDQN 则有两个Q网络第一个Q网络 $Q$ 决定哪一个动作的Q值最大决定动作后Q值用 $Q$ 算出来式 7.2$$ Q\left(s_{t}, a_{t}\right) \longleftrightarrow r_{t}Q^{\prime}\left(s_{t1}, \arg \max{a} Q\left(s{t1}, a\right)\right) \tag{7.2} $$如果 $Q$ 高估了它选出的动作 $a$只要 $Q$ 没有高估这个动作的值算出来的就还是正常值反过来若 $Q$ 高估了某个动作只要 $Q$ 不选它就没问题。DDQN 相较于DQN的更改最少几乎没有增加任何运算量也不需要新网络原来就有两个网络只需把用目标网络 $Q$ 找使 Q 值最大的 $a$改为用另一个会更新的Q网络找使 Q 值最大的 $a$。如果只选一个技巧一般都会选DDQN因为其极易实现。7.1.3 源码对照DoubleDQN 的更新核心仓库 notebooks/DoubleDQN.ipynb 完整实现了该逻辑核心更新代码1.3 节DoubleDQN.update为q_value_batch self.policy_net(state_batch).gather(dim1, indexaction_batch) # 实际Q值 next_q_value_batch self.policy_net(next_state_batch) # 策略网络选动作 next_target_value_batch self.target_net(next_state_batch) # 目标网络算价值 # 将策略网络Q值最大的动作对应的目标网络Q值作为期望的Q值 next_target_q_value_batch next_target_value_batch.gather( 1, torch.max(next_q_value_batch, 1)[1].unsqueeze(1)) expected_q_value_batch reward_batch self.gamma * next_target_q_value_batch * (1 - done_batch) loss nn.MSELoss()(q_value_batch, expected_q_value_batch)其中policy_net会更新负责torch.max(next_q_value_batch, 1)[1]选出最优动作target_net固定住负责取该动作的Q值——正是式(7.2)的代码形态。其余部分MLP网络、ReplayBuffer、ε-贪心采样、目标网络定期load_state_dict拷贝参数与DQN完全一致印证了更改最少的说法。该 notebook 在 CartPole-v1 上的一组默认超参数第 4 节Config可直接参考algo_name DoubleDQN; env_name CartPole-v1; seed 1 train_eps 100; test_eps 10; max_steps 200 gamma 0.99; lr 0.0001 epsilon_start 0.95; epsilon_end 0.01; epsilon_decay 500 buffer_size 10000; batch_size 64; target_update 4; hidden_dim 256 device cuda if torch.cuda.is_available() else cpu其中epsilon按epsilon_end (epsilon_start - epsilon_end) * exp(-sample_count / epsilon_decay)指数衰减target_update为策略网络参数拷贝到目标网络的频率以采样次数计。训练 100 回合后测试 10 回合基本可稳定拿到 200 分满分。7.2 竞争深度Q网络拆分为状态价值与优势7.2.1 网络结构V(s) 与 A(s,a) 两条路径竞争深度Q网络与原始DQN唯一的差别是改变了网络架构。原DQN输入状态直接输出每个动作的Q值Dueling DQN 不直接输出Q值而是分成两条路径第一条路径输出一个与输入 $s$ 有关的标量 $V(\boldsymbol{s})$第二条路径输出一个向量 $\boldsymbol{A}(\boldsymbol{s},\boldsymbol{a})$每个动作一个值。二者相加得到 $\boldsymbol{Q}(\boldsymbol{s},\boldsymbol{a})$$$ \boldsymbol{Q}(\boldsymbol{s},\boldsymbol{a}) V(\boldsymbol{s}) \boldsymbol{A}(\boldsymbol{s},\boldsymbol{a}) $$假设只有 4 个状态、3 个动作$\boldsymbol{Q}(\boldsymbol{s},\boldsymbol{a})$ 可看成一个表格原文档图 7.4把 $V(\boldsymbol{s})$ 加到 $\boldsymbol{A}(\boldsymbol{s},\boldsymbol{a})$ 的每一列就得到 Q 值。7.2.2 为什么更有效率训练网络时我们真正能修改的是 $V(\boldsymbol{s})$ 与 $\boldsymbol{A}(\boldsymbol{s},\boldsymbol{a})$ 的值。假设希望 Q 表格中第一行第二列由 3 变 4、第二行第二列由 −1 变 0此时可能只改 $V(\boldsymbol{s})$ 即可从 0 变 1于是 Q 表格中第三个动作的值−2→−1也被顺带修改了。也就是说即使某个状态只采样到两个动作、没采样到第三个动作第三个动作的 Q 值也会被更新——不需要把所有的状态-动作对都采样就能用更高效的方式估计 Q 值。因此 Dueling DQN 是一个使用数据比较有效率的方法。7.2.3 可辨识性问题与零均值化约束一个潜在问题是智能体可能学到 $V(\boldsymbol{s})0$、$\boldsymbol{A}(\boldsymbol{s},\boldsymbol{a})Q$那样Dueling结构就退化成原DQN毫无好处。为避免这个问题要给 $\boldsymbol{A}(\boldsymbol{s},\boldsymbol{a})$ 加约束让它的更新比较麻烦从而迫使网络倾向于用 $V(\boldsymbol{s})$ 解决问题。最直觉的约束是让 $\boldsymbol{A}(\boldsymbol{s},\boldsymbol{a})$ 每一列的和为 0此时 $V(\boldsymbol{s})$ 可理解为每列 Q 值的平均值由于每列和恒为 0无法让某列所有元素都加 1网络就被迫去更新 $V(\boldsymbol{s})$。实现上就是零均值化假设 3 个动作输出 $[7,3,2]^{\mathrm{T}}$先求均值 (732)/34每个元素减 4 得 $[3,-1,2]^{\mathrm{T}}$再与 $V(\boldsymbol{s})$ 相加得到Q值。该步骤没有参数、是网络的一部分可以随网络一起反向传播训练。7.2.4 源码对照DuelingNet 的结构与组合公式仓库 notebooks/DuelingDQN.ipynb 的DuelingNet正是共享隐藏层 价值/优势两个分支的实现class DuelingNet(nn.Module): def __init__(self, n_states, n_actions, hidden_dim128): super(DuelingNet, self).__init__() self.hidden_layer nn.Sequential(nn.Linear(n_states, hidden_dim), nn.ReLU()) # advantage 分支 self.advantage_layer nn.Sequential( nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, n_actions)) # value 分支 self.value_layer nn.Sequential( nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, 1)) def forward(self, state): x self.hidden_layer(state) advantage self.advantage_layer(x) value self.value_layer(x) return value advantage - advantage.mean() # 零均值化forward末尾的value advantage - advantage.mean()即带约束的组合公式notebook 中给出的可辨识形式$$ Q(S, A, w, \alpha, \beta)V(S, w, \alpha)\left(A(S, A, w, \beta)-\frac{1}{\mathcal{A}} \sum_{a^{\prime} \in \mathcal{A}} A\left(S, a^{\prime}, w, \beta\right)\right) $$模型结构图可参考 notebooks/figs/duelingdqn_model.png左普通三层MLP右Dueling 双分支结构。该 notebook 在 CartPole-v1 上使用gamma0.95、lr0.0001、memory_capacity10000、batch_size64、target_update800、hidden_dim256训练 100 回合后测试 10 回合同样能达到 200 满分验证了数据利用效率更高的实际效果。7.3 优先级经验回放让难样本更大概率被采样7.3.1 动机原来从回放缓冲区采样训练Q网络时是均匀采样这不一定是最好策略。有些数据之前采样过、发现其时序差分误差TD误差特别大——即网络的输出与目标之间的差距大说明这些数据比较不好训练。既然不好训练就应该给它们更大的被采样概率优先权。需要注意的是PER不仅改变了采样数据的分布还改变了更新参数的方法训练过程因为采样分布变了必须用重要性采样权重修正梯度偏差。7.3.2 源码对照SumTree 与优先级更新仓库 notebooks/PER_DQN.ipynb 给出了完整的 PER 实现核心数据结构是SumTree线段树/求和树用于按优先级快速采样。关键设计第 2 节PrioritizedReplayBuffer如下self.alpha 0.6 # 优先级指数控制优先级对采样的影响程度 self.beta 0.4 # 重要性采样权重指数IS weights self.epsilon 0.01 # 避免零优先级的常数 self.abs_err_upper 1. # 用于对TD误差进行截断 ... p (np.abs(error) self.epsilon) ** self.alpha # 由TD误差计算优先级 ... self.beta np.min([1., self.beta self.beta_increment_per_sampling]) # beta随采样逐步增大 is_weights np.power(self.tree.n_entries * sampling_probabilities, -self.beta) # 重要性采样权重要点SumTree 采样根据根节点优先级和采样样本数划分采样区间逐层与节点优先级对比最终得到要采样的叶子样本notebook 中 1.2 节有图解说明优先级更新采样后用本批 TD 误差ps np.power(clipped_errors, self.alpha)回写树节点重要性采样权重由于改变了采样分布更新时必须乘以is_weights以修正偏差beta从 0.4 随采样逐步线性增至 1.0abs_err_upper1.用于把 TD 误差截断在 $[-1,1]$防止个别异常样本优先级过大。7.4 多步方法在蒙特卡洛与时序差分之间取得平衡蒙特卡洛方法与时序差分方法各有优劣多步方法multi-step在二者之间取得平衡。TD 方法只走一步在状态 $s_t$ 采取动作 $a_t$ 得到奖励 $r_t$进入 $s_{t1}$多步方法则保存 $N$ 个步骤的数据一直记录到在 $s_{tN}$ 采取 $a_{tN}$、得到 $r_{tN}$、进入 $s_{tN1}$。更新时让 $Q(s_t,a_t)$ 与目标值越接近越好其中 $\hat{Q}$ 计算的不是 $s_{t1}$ 而是 $s_{tN1}$ 的奖励目标值再加上多步奖励之和$$ \sum_{t^{\prime}t}^{tN} r_{t^{\prime}} $$即从时间 $t$ 到 $tN$ 共 $N1$ 个奖励的和。好处TD 只采样一步接下来都是Q值估测出来的多步方法采样 $N$ 步才估测估测部分造成的影响更小坏处与蒙特卡洛方法一样$N$ 项奖励加起来方差会变大权衡$N$ 是一个可调的超参数例如 3 步还是 5 步用于在方差与Q值不精确之间取得平衡。7.5 噪声网络在参数空间而非动作空间探索7.5.1 基本思想$\varepsilon$-贪心是在动作空间上加噪声做探索。噪声网络Noisy Net则是在参数空间上加噪声每个回合开始、智能体与环境交互之前给Q函数网络的每个参数加一个高斯噪声Gaussian noise把原Q函数变成噪声Q函数 $\tilde{Q}$。使用噪声网络执行的动作为$$ a\underset{a}{\arg \max} \tilde{Q}(s, a) $$关键约定每个回合开始时采样噪声随后用固定的噪声网络玩完整个回合直到游戏结束才重新采样噪声在一个回合内不能改变。OpenAI 与 DeepMind 几乎同时提出该方法两篇论文均发表于 ICLR 2018区别仅在于加噪声的方式——OpenAI 直接给每个权重加高斯噪声较简单DeepMind 的噪声由一组参数控制、网络可以自己决定噪声加多大较复杂但概念一致。7.5.2 依赖状态的探索与ε-贪心的本质差异这带来了与动作空间采样方法的本质差异。在 $\varepsilon$-贪心中给定同样的状态智能体可能执行不同的动作有时用Q函数、有时随机这在真实世界中是不正常的——真实策略给定相同状态应有相同回应。而在参数上加噪声时同一个回合内网络参数固定看到相同或类似的状态就会采取相同的动作这被称为依赖状态的探索state-dependent exploration动作噪声只是随机乱试参数噪声则是系统地尝试——比如某状态每次向左试下个回合看到同样状态再向右试是系统性地探索环境。7.5.3 源码对照NoisyLinear 与回合级噪声重置仓库 notebooks/NoisyDQN.ipynb 实现了NoisyLinear带噪声的全连接层与噪声网络NoisyNetnoisy_fc1/2/3并在forward中应用噪声。回合级噪声重置逻辑体现在self.policy_net.reset_noise() # 训练每回合开始时重置策略网络噪声 self.target_net.reset_noise() # 目标网络同样重置reset_noise内部用_scale_noise生成与参数同形状的高斯噪声epsilon_in/epsilon_out拷贝到weight_epsilon、bias_epsilon上。noise 在网络训练时作为可学习的参数一起反向传播——这正是网络可以自己决定噪声要加多大的实现基础。该 notebook 的配置中epsilon_start0.95, epsilon_end0.01, epsilon_decay500依然保留但探索主要依赖网络内部噪声默认还提供gamma0.95, lr0.0001, buffer_size100000, batch_size64, target_update4, hidden_dim256等参数。7.6 分布式Q函数对奖励分布而非期望建模7.6.1 为什么只建模期望不够Q函数是累积奖励的期望值但环境有随机性在某状态采取某动作游戏结束时统计所有可能奖励得到的是一个分布例如奖励为 0 的概率很高−10 和 10 的概率较低。对这个分布取平均才是Q值。不同的分布可以有相同的平均值——假设只用Q值的期望代表整个奖励会丢失信息无法对奖励分布进行建模见原文档图 7.8平均值相同但形状不同的两个分布。7.6.2 做法输出落在某个长条中的概率分布式Q函数直接对分布建模假设奖励分布落在某个范围内如 −10 ~ 10把它拆成一个个长条例如每个动作的奖励空间拆成 5 个长条Q函数的输出变成预测在某状态采取某动作得到的奖励落在某一个长条内的概率。以 3 个动作 $a_1,a_2,a_3$ 为例输入一个状态分别输出三组概率绿色/红色/蓝色长条每组概率之和为 1高度代表落在该长条内的概率。测试时选平均值最大的动作执行。额外的好处是还可以利用分布信息比如方差大的动作风险高——在两个动作平均值差不多时可以选风险更小的动作执行从而训练出规避风险的策略。7.7 彩虹把全部技巧组合起来7.7.1 组合与消融彩虹Rainbow把前述方法全部组合使用原DQN算一种颜色加上 DDQN、PER、Dueling、多步、Noisy、分布式Q函数共 7 种颜色原文档图 7.10。横轴是训练帧数纵轴是十几个雅达利小游戏分数的中位数取中位数而非平均是因为不同游戏分数差距很大取平均会让某几个游戏控制结果。单看各种方法灰色普通DQN性能较差噪声DQNnoisy DQN比DQN好很多紫色DDQN挺有效优先级双DQNprioritized DDQN、竞争双DQNdueling DDQN、分布式DQNdistributional DQN性能都较高异步优势演员-评论员A3C属于演员-评论员方法将在本书第九章详细介绍A3C 内部本身就含多步方法所以图 7.10 中没有单独的多步方法曲线——实现A3C 就等于实现了多步方法。这些方法彼此不冲突全部叠加就是彩虹方法性能很好。7.7.2 去掉一种方法会怎样把全部方法组合后逐一去掉其中一种方法可以判断它的贡献原文档图 7.11虚线为去掉某方法后的结果去掉多步方法后性能掉很多去掉优先级经验回放后掉下来去掉**分布分布式Q函数**后也掉下来——有趣的是训练初期分布方法与其他方法速度差不多去掉它训练不会变慢但最终性能收敛在比较差的地方去掉噪声网络后性能差一点去掉竞争深度Q网络后性能差一点去掉双深度Q网络却没什么差别。为什么 DDQN 在组合中作用变小因为分布式DQN本质上就不会高估奖励它输出的是分布的范围范围必然受限如 −10 ~ 10若真实奖励超过 10比如 100就会被当作没看到而丢弃因此极端的大值奖励被丢弃不会高估奖励、反而会低估奖励。既然用了分布式Q函数后已无高估问题DDQN 的用武之地就变小了。7.8 综合实践把进阶技巧用在 CartPole 上7.8.1 实践项目环境CartPole-v0仓库 第7章实践项目project2.md建议使用 Double-DQN 解决 CartPole-v0即建立两个初始参数相同的全连接网络target_net与policy_net。CartPole-v0 是 OpenAI Gym 经典环境通过向左action0或向右action1推车保持平衡动作空间由两个动作组成每进行一个 step 得 1 奖励无法保持平衡时doneTrue本次 episode 失败。理想状态下每个 episode 至少进行 200 个 step即每个 episode 的奖励总和至少 200、step 数至少 200。环境建立如下import gym env gym.make(CartPole-v0) env.seed(1) # 设置env随机种子 n_states env.observation_space.shape[0] # 总状态数 n_actions env.action_space.n # 总动作数7.8.2 强化学习基本训练循环项目文档给出的训练主循环结构记录奖励、滑动平均、每回合更新目标网络rewards [] # 记录总的rewards moving_average_rewards [] # 记录滑动平均处理后的rewards ep_steps [] for i_episode in range(1, cfg.max_episodes1): # cfg.max_episodes 最大训练episode数 state env.reset() # reset环境状态 ep_reward 0 for i_step in range(1, cfg.max_steps1): # cfg.max_steps 每episode最大步数 action agent.select_action(state) # 根据当前state选择action next_state, reward, done, _ env.step(action) # 更新环境参数 ep_reward reward agent.memory.push(state, action, reward, next_state, done) # transition存入memory state next_state # 跳转到下一个状态 agent.update() # 每步更新网络 if done: break # 更新target network复制DQN中的所有weights and biases if i_episode % cfg.target_update 0: # cfg.target_update 目标网络更新频率 agent.target_net.load_state_dict(agent.policy_net.state_dict()) print(Episode:, i_episode, Reward: %i % int(ep_reward), n_steps:, i_step, done: , done, Explore: %.2f % agent.epsilon) ep_steps.append(i_step) rewards.append(ep_reward) # 计算滑动窗口的reward if i_episode 1: moving_average_rewards.append(ep_reward) else: moving_average_rewards.append( 0.9*moving_average_rewards[-1]0.1*ep_reward)7.8.3 结果可视化与超参数记录训练后应绘制reward 及滑动平均 reward 随 episode 的变化曲线并记录超参数写成报告。项目文档在 docs/chapter7/assets 目录给出了训练train与测试eval的参考曲线图训练曲线rewards_train.png、moving_average_rewards_train.png、steps_train.png评估曲线rewards_eval.png、moving_average_rewards_eval.png、steps_eval.png。其中滑动平均的递推式0.9 * moving_average_rewards[-1] 0.1 * ep_reward与 DoubleDQN.ipynb、DuelingDQN.ipynb 中smooth(data, weight0.9)的平滑方式一致即指数加权滑动平均。此外也可以用 TensorBoard 查看训练过程的奖励与步数曲线见 project2.md 末尾的截图说明。7.9 总结与选型建议技巧解决的核心问题改动点实现成本Double DQNQ值过估计目标Q值的计算方式选动作与算价值解耦极低只改几行Dueling DQN数据利用效率低网络结构拆成 V(s) A(s,a) 并零均值化低改网络结构Prioritized Replay难样本采样不足采样分布 重要性采样权重中需 SumTreeMulti-stepTD偏差与MC方差折中保存并累加 N 步奖励低$N$ 为超参数Noisy Net探索不合理参数空间加噪声、回合级重置中需自定义带噪声层Distributional Q忽视奖励分布信息输出分布而非期望较高需分布投影Rainbow综合上述全部收益全部叠加高工程量大若只选一个技巧首选 DDQN改动最少、几乎不增加运算量却最直接地缓解Q值高估Dueling DQN 与 PER 通常都能带来稳定收益且互不冲突多步方法N≈3~5是低成本高收益的折中A3C 等演员-评论员方法内部本身就包含多步Noisy Net 与分布式Q函数更进阶后者还能支持风险敏感选低方差动作的策略Rainbow 是这些方法的组合上限消融实验表明多步、PER、分布式贡献最大而在使用分布式Q函数后 DDQN 的边际收益变小。所有技巧的完整可运行实现与默认超参数均可从仓库 notebooks 目录下对应的DoubleDQN、DuelingDQN、PER_DQN、NoisyDQN等 notebook 中直接获取并在 CartPole 系列环境中验证配套的章节关键词与习题含面试题见 第7章问答文档可进一步自测对每个技巧原理的掌握程度。赞分享教程机器学习深度学习【免费下载链接】easy-rl强化学习中文教程蘑菇书在线阅读地址https://datawhalechina.github.io/easy-rl/项目地址https://gitcode.com/gh_mirrors/ea/easy-rl点击查看免费下载相关推荐easy-rl 蘑菇书第七章深度Q网络进阶技巧全解——Double DQN、Dueling DQN、PER、噪声网络与彩虹easy rl 蘑菇书第七章深度Q网络进阶技巧全解——Double DQN、Dueling DQN、PER、噪声网络与彩虹 本文以蘑菇书easy rl 第教程机器学习深度学习Easy-RL深度Q网络DQN及其进阶技巧全解析Easy RL深度Q网络DQN及其进阶技巧全解析 本文全面解析了深度Q网络DQN及其核心改进技术。DQN通过结合深度学习与Q学习解决了高维状态空间下的价人工智能强化学习深度学习教程Easy-RL项目深度Q网络进阶技巧详解Easy RL项目深度Q网络进阶技巧详解 深度Q网络 DQN 作为强化学习中的重要算法在实际应用中存在多种改进方法。本文将系统介绍Easy RL项目中提出的7教程机器学习深度学习上一篇Factorio蓝图可视化工具打造你的工厂艺术下一篇从0到1掌握ahk2_lib解放Windows自动化潜能的全栈工具库创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考