- 教程
- 机器学习
- 深度学习
【免费下载链接】easy-rl
强化学习中文教程(蘑菇书🍄),在线阅读地址:https://datawhalechina.github.io/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{t+1}, 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_{t+1}, \arg \max{a} Q\left(s{t+1}, 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(dim=1, index=action_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}}$,先求均值 (7+3+2)/3=4,每个元素减 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_dim=128): 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 上使用gamma=0.95、lr=0.0001、memory_capacity=10000、batch_size=64、target_update=800、hidden_dim=256,训练 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.0; abs_err_upper=1.用于把 TD 误差截断在 $[-1,1]$,防止个别异常样本优先级过大。
7.4 多步方法:在蒙特卡洛与时序差分之间取得平衡
蒙特卡洛方法与时序差分方法各有优劣,多步方法(multi-step)在二者之间取得平衡。TD 方法只走一步:在状态 $s_t$ 采取动作 $a_t$ 得到奖励 $r_t$,进入 $s_{t+1}$;多步方法则保存 $N$ 个步骤的数据,一直记录到在 $s_{t+N}$ 采取 $a_{t+N}$、得到 $r_{t+N}$、进入 $s_{t+N+1}$。更新时让 $Q(s_t,a_t)$ 与目标值越接近越好,其中 $\hat{Q}$ 计算的不是 $s_{t+1}$ 而是 $s_{t+N+1}$ 的奖励,目标值再加上多步奖励之和:
$$ \sum_{t^{\prime}=t}^{t+N} r_{t^{\prime}} $$
即从时间 $t$ 到 $t+N$ 共 $N+1$ 个奖励的和。
- 好处: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(带噪声的全连接层)与噪声网络NoisyNet(noisy_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_start=0.95, epsilon_end=0.01, epsilon_decay=500依然保留,但探索主要依赖网络内部噪声;默认还提供gamma=0.95, lr=0.0001, buffer_size=100000, batch_size=64, target_update=4, hidden_dim=256等参数。
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)性能较差;
- 噪声DQN(noisy DQN)比DQN好很多;
- 紫色(DDQN)挺有效;
- 优先级双DQN(prioritized DDQN)、竞争双DQN(dueling DDQN)、分布式DQN(distributional 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 经典环境:通过向左(action=0)或向右(action=1)推车保持平衡,动作空间由两个动作组成;每进行一个 step 得 +1 奖励,无法保持平衡时done=True,本次 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_episodes+1): # cfg.max_episodes 最大训练episode数 state = env.reset() # reset环境状态 ep_reward = 0 for i_step in range(1, cfg.max_steps+1): # 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, weight=0.9)的平滑方式一致,即指数加权滑动平均。此外也可以用 TensorBoard 查看训练过程的奖励与步数曲线(见 project2.md 末尾的截图说明)。
7.9 总结与选型建议
| 技巧 | 解决的核心问题 | 改动点 | 实现成本 |
|---|---|---|---|
| Double DQN | Q值过估计 | 目标Q值的计算方式(选动作与算价值解耦) | 极低(只改几行) |
| Dueling DQN | 数据利用效率低 | 网络结构拆成 V(s) + A(s,a) 并零均值化 | 低(改网络结构) |
| Prioritized Replay | 难样本采样不足 | 采样分布 + 重要性采样权重 | 中(需 SumTree) |
| Multi-step | TD偏差与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/
相关推荐
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
教程机器学习深度学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考