☰
再聊 Q-Learning:用神经网络替代表格的 DQN 原理与实战
2026/10/20 9:45:46 网站建设 项目流程

大约在 2017 年前后,深度强化学习在游戏、机器人控制等领域频繁刷榜,DQN 的论文也是那时候开始被反复阅读。很多初学者一开始接触的是“Q-Learning 表格法”,在简单环境里用二维表记录每个状态和动作的价值,效果还行,一旦环境状态变多,比如连续坐标、像素画面,表就存不下了。这时候就需要用神经网络来拟合 Q 值函数,这就是 DQN 的核心思想。

本文是这个强化学习入门系列的第 49 篇,主题是“再聊 Q-Learning”。所谓“再聊”,是把大家熟悉的表格型 Q-Learning 放到深度学习视角下重新审视:表格为什么失效,神经网络如何替代表格,DQN 在实现上解决了哪些 Q-Learning 原生的问题。文章会从核心概念、环境准备、原理拆解、完整可运行的 DQN 实战代码、常见问题、工程建议几个方面展开。适合有一定 Python 基础、了解基本强化学习要素,但还不太清楚 DQN 代码细节的学习者。

1. 背景与核心概念

1.1 强化学习的基本要素回顾

强化学习的任务是让智能体通过与环境交互来学习一种最优策略。一个标准流程是:智能体观察环境状态,选择一个动作,环境返回下一个状态和奖励,循环往复。

这里有几个核心名词需要先统一:

  • 状态:智能体当前观察到的环境信息。
  • 动作:智能体可以选择的操作。
  • 奖励:环境对动作的即时反馈。
  • 策略:状态到动作的映射关系。
  • 回报:未来所有奖励的折扣累计值。

在 Q-Learning 中,我们直接估计一个函数 Q(s,a),表示在状态 s 下执行动作 a,之后一直采取最优策略所能获得的期望回报。有了这个函数,智能体的决策就变得非常简单:在状态 s 下选择 Q 值最大的动作。

1.2 表格型 Q-Learning 的基本方法

经典的 Q-Learning 使用一张二维表格来存储 Q 值:

  • 行代表状态。
  • 列代表动作。
  • 单元格代表 Q(s,a)。

更新公式是:

Q(s,a) <- Q(s,a) + alpha * (r + gamma * max_a' Q(s',a') - Q(s,a))

这个公式中:

  • alpha 表示学习率。
  • gamma 表示折扣因子。
  • r 是当前奖励。
  • s' 是下一个状态。
  • max_a' Q(s',a') 表示下一状态所有动作中的最大 Q 值。

表格法在小规模离散状态空间里非常好用,比如经典的迷宫问题、悬崖行走问题。状态数量有限,表格能完整记录所有情况,而且更新公式简单,实现难度低。

但表格法有一个天然瓶颈:状态和动作的组合数量一旦变大,表格容量会爆炸。CartPole 这种环境的状态本身就包含车的位置、速度、杆的角度、角速度四个连续值,无法直接枚举;Atari 游戏的画面更是超过 10 万像素,表格连存储都不可能。

1.3 从 Q-Learning 到 DQN 的转变

DNQ,也就是 Deep Q-Network,做的事情是“用一个神经网络来替代那张 Q 值表”。神经网络的输入是状态,输出是每个可能的动作对应的 Q 值。

这种做法有几个明显好处:

  • 神经网络可以处理连续状态输入。
  • 神经网络可以通过训练自动提取特征,不需要人工设计状态特征。
  • 神经网络具备泛化能力,相似的状态会得到相近的 Q 值输出。

但直接用神经网络替换表格并不是那么简单。2013 年 DeepMind 提出 DQN 时,主要解决了两个关键问题:一是经验回放,二是目标网络。这两个机制让神经网络的训练过程变得稳定,也让 DQN 能够在许多高维状态空间中真正跑起来。

2. 环境准备与版本说明

本文的实战以 CartPole 环境为例。CartPole 是强化学习领域最常用的入门环境,目标是通过左右移动小车,让杆保持竖直不倒。

建议的环境和依赖如下:

  • 操作系统:Windows / macOS / Linux 均可。
  • Python 版本:3.9 及以上。
  • 深度学习框架:PyTorch 2.x。
  • 环境库:Gymnasium。
  • 辅助库:NumPy、Matplotlib。

版本需要根据你的项目实际情况调整。早期版本的 OpenAI Gym 和现在的 Gymnasium 在 API 上有一些差别,最典型的是env.reset()返回值的差异。本文示例以较新的 Gymnasium 接口为准。如果你还在使用旧版 gym,需要把代码中的环境交互部分改成对应格式,后面会在常见问题里说明。

安装命令如下:

pip install torch pip install gymnasium pip install numpy matplotlib

如果使用国内镜像源,可以加速安装:

pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple

安装完成后,可以用下面这段代码确认 Gymnasium 能正常创建环境:

import gymnasium as gym env = gym.make("CartPole-v1") state, info = env.reset() print("状态维度:", len(state)) print("动作空间:", env.action_space) print("初始状态:", state) env.close()

正常输出大致如下:

状态维度: 4 动作空间: Discrete(2) 初始状态: [-0.01234 0.02103 -0.01903 -0.00221]

这里状态是一个长度为 4 的数组,包含小车位置、小车速度、杆角度、杆角速度。动作空间只有两个动作:向左推和向右推。

3. DQN 核心原理拆解

3.1 经验回放:打破样本相关性

深度神经网络训练的前提是样本尽量独立同分布。但强化学习的数据来自连续交互,相邻时间步的状态、动作、奖励高度相关。如果每拿到一条经验就立刻更新一次网络,模型会在最近一段轨迹上反复“偏科”,导致训练不稳定甚至遗忘之前学到的内容。

经验回放的思想是维护一个固定容量的缓冲区,把每次交互得到的五元组存储起来,训练时从这个缓冲区中随机采样一批数据来更新网络。这样做有两个作用:

  • 打乱数据之间的相关性,让训练更接近监督学习中的随机梯度下降。
  • 提高数据利用率。同一条经验可以多次被采样使用,而不是用一次就丢弃。

缓冲区容量是经验回放的关键参数。容量太小,采样数据仍然偏向近期经验;容量太大,又可能导致大量旧经验占据缓冲区,新经验的占比过低。一般推荐用 10000 到 100000 之间的值,具体需要根据环境和设备内存调整。

3.2 目标网络:稳定学习目标

表格型 Q-Learning 的更新目标就是 Q 值表本身,更新一步,表格里的值变一点,问题不大。但神经网络更新时,如果训练目标也在不断变化,模型就很难收敛。DQN 更新的目标是:

r + gamma * max_a' Q_target(s', a')

这里的 Q_target 如果还是同一个网络,那么每次梯度更新都会同时改变目标值,相当于“边追边移动的靶子”,训练容易发散。

DQN 的做法是维护一个与主网络结构相同、初始参数也相同的目标网络。目标网络不参与梯度更新,只用来计算 TD 目标。每隔一定步数,把主网络的参数复制给目标网络。

一个常见困惑是:

  • 为什么不能直接让目标网络每步都跟着主网络更新?
  • 为什么要隔一段时间才同步一次?

答案很直接:如果每步都同步,目标网络和主网络就完全一样,失去了“固定目标”的意义。隔一段时间同步,能让目标在短期内保持相对稳定,网络在朝着一个相对固定的方向训练一段时间后,再切换到新的目标。这个周期一般设为 500 到 2000 步之间。

3.3 DQN 的损失函数

DQN 的损失函数本质上是一个均方误差:

Loss = E[(r + gamma * max_a' Q_target(s', a') - Q_policy(s, a))^2]

这里的 Q_policy 是主网络对当前状态下实际执行动作 a 的预测 Q 值,目标是计算出的 TD 目标。训练过程就是让主网络的预测值逐步逼近 TD 目标。

需要特别留意的是,目标中的 max 运算,是 DQN 在后续被提出来的一些问题的重要根源。使用 max 会选择所有动作中 Q 值最大的那个,但因为 Q 值是估计值,存在噪声,max 会把噪声往大的方向放大,造成 Q 值过高估计。这个问题在后续的 Double DQN 中会专门解决,本文不做过多展开,后面会根据情况适当提及。

3.4 探索与利用的平衡

Q-Learning 类和 DQN 类方法都面临探索与利用的平衡问题。如果智能体总是选择当前 Q 值最大的动作,它就永远发现不了更好的策略。如果一直乱选,又无法积累有效经验。

最常见的策略是 epsilon-greedy:

  • 以概率 epsilon 随机选择动作进行探索。
  • 以概率 1 - epsilon 选择 Q 值最大的动作进行利用。

训练初期 epsilon 通常设置得比较高,比如 1.0,让智能体充分探索环境;随着训练进行,逐步衰减到某个最小值,比如 0.01。衰减方式可以按固定乘子逐 episode 衰减,也可以按训练步数衰减,取决于具体场景。

epsilon 衰减速度对训练效果影响很大。衰减太快,智能体可能还没充分探索就进入“利用模式”,陷入局部最优。衰减太慢,智能体始终在随机试错,奖励曲线提升会很慢。对于 CartPole 这类简单环境,每 episode 乘以 0.995 左右是一个比较常见的起点配置。

3.5 表格方法与函数逼近的对比

为了让大家更直观地理解,这里把表格型 Q-Learning 和 DQN 放在一起对比:

维度表格型 Q-LearningDQN
Q 值存储二维表格神经网络参数
状态输入离散索引连续向量或图像
泛化能力无,未访问状态无从估计有,相近状态输出相近
训练数据实时更新经验回放随机采样
稳定性天然稳定需要目标网络等机制
适用规模小规模离散状态大规模高维状态

这个对比可以帮助理解文章的标题为什么要用“再聊”:Q-Learning 的核心思想在 DQN 中并没有改变,改变的只是 Q 函数的表现形式和训练方式。

4. 完整实战案例

下面进入本文的核心部分:用 PyTorch 实现一个可以训练的 DQN,并在 CartPole 环境中验证效果。代码会拆成多个文件,方便后续扩展和维护。

4.1 创建项目结构

在任意目录下创建项目文件夹,名称建议为dqn_cartpole。项目结构如下:

dqn_cartpole/ ├── dqn_model.py # 神经网络定义 ├── replay_buffer.py # 经验回放缓冲区 ├── dqn_agent.py # DQN 智能体 ├── train.py # 训练主循环 └── requirements.txt # 依赖清单

如果只想快速验证效果,也可以把所有代码写在一个文件里。但按上述结构拆分,逻辑更清晰,也更接近工程项目的组织方式。

4.2 添加依赖配置

在 requirements.txt 中写入:

torch gymnasium numpy matplotlib

安装依赖:

pip install -r requirements.txt

4.3 编写神经网络模型

文件路径:dqn_model.py

DQN 的输入是状态向量,输出是所有动作的 Q 值。对于 CartPole 来说,输入维度是 4,输出维度是 2。中间使用两个隐藏层,每层 128 个神经元,激活函数选择 ReLU。

import torch.nn as nn class DQN(nn.Module): """将状态映射为各个动作的 Q 值。""" def __init__(self, state_dim, action_dim, hidden_dim=128): super(DQN, self).__init__() self.net = nn.Sequential( nn.Linear(state_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, action_dim) ) def forward(self, x): return self.net(x)

这里模型结构相对简单,因为 CartPole 本身复杂度不高。如果后面想尝试 Atari 游戏,则需要换成卷积神经网络,输入也会从向量变成图像张量。

4.4 编写经验回放缓冲区

文件路径:replay_buffer.py

回放缓冲区使用双端队列实现,容量到达上限后,新的数据会覆盖最旧的数据。采样时使用随机采样,保证训练数据的随机性。

import random from collections import deque class ReplayBuffer: """存储和采样历史经验。""" def __init__(self, capacity): self.buffer = deque(maxlen=capacity) def push(self, state, action, reward, next_state, done): self.buffer.append((state, action, reward, next_state, done)) def sample(self, batch_size): batch = random.sample(self.buffer, batch_size) states = [item[0] for item in batch] actions = [item[1] for item in batch] rewards = [item[2] for item in batch] next_states = [item[3] for item in batch] dones = [item[4] for item in batch] return states, actions, rewards, next_states, dones def __len__(self): return len(self.buffer)

这里选择直接返回 Python 列表,方便在训练循环中转换为张量。实践中也有人用 NumPy 存储来提升效率,但对 CartPole 这种小规模任务,列表已经足够。

4.5 编写 DQN 智能体

文件路径:dqn_agent.py

这个类是整个 DQN 算法的核心。它需要完成几件事:

  • 维护主网络和目标网络。
  • 根据 epsilon-greedy 策略选择动作。
  • 执行一次梯度更新。
  • 定期同步目标网络。
import torch import torch.nn as nn import torch.optim as optim import numpy as np from dqn_model import DQN class DQNAgent: def __init__(self, state_dim, action_dim, lr=1e-3, gamma=0.99, epsilon=1.0, epsilon_min=0.01, epsilon_decay=0.995, target_update=100): self.action_dim = action_dim self.gamma = gamma self.epsilon = epsilon self.epsilon_min = epsilon_min self.epsilon_decay = epsilon_decay self.target_update = target_update self.update_counter = 0 self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu") self.policy_net = DQN(state_dim, action_dim).to(self.device) self.target_net = DQN(state_dim, action_dim).to(self.device) self.target_net.load_state_dict(self.policy_net.state_dict()) self.target_net.eval() self.optimizer = optim.Adam(self.policy_net.parameters(), lr=lr) self.loss_fn = nn.MSELoss() def select_action(self, state): if np.random.rand() < self.epsilon: return np.random.randint(self.action_dim) state_tensor = torch.FloatTensor(state).unsqueeze(0).to(self.device) with torch.no_grad(): q_values = self.policy_net(state_tensor) return int(torch.argmax(q_values).item()) def update(self, replay_buffer, batch_size): if len(replay_buffer) < batch_size: return states, actions, rewards, next_states, dones = replay_buffer.sample(batch_size) states = torch.FloatTensor(np.array(states)).to(self.device) actions = torch.LongTensor(np.array(actions)).unsqueeze(1).to(self.device) rewards = torch.FloatTensor(np.array(rewards)).unsqueeze(1).to(self.device) next_states = torch.FloatTensor(np.array(next_states)).to(self.device) dones = torch.FloatTensor(np.array(dones)).unsqueeze(1).to(self.device) current_q = self.policy_net(states).gather(1, actions) with torch.no_grad(): next_q = self.target_net(next_states).max(1, keepdim=True)[0] target_q = rewards + self.gamma * next_q * (1 - dones) loss = self.loss_fn(current_q, target_q) self.optimizer.zero_grad() loss.backward() nn.utils.clip_grad_norm_(self.policy_net.parameters(), max_norm=10) self.optimizer.step() self.update_counter += 1 if self.update_counter % self.target_update == 0: self.target_net.load_state_dict(self.policy_net.state_dict()) def update_epsilon(self): self.epsilon = max(self.epsilon_min, self.epsilon * self.epsilon_decay)

几个实现细节需要重点解释。

第一,next_q = self.target_net(next_states).max(1, keepdim=True)[0]计算的是下一状态的最大 Q 值,对应 Q-Learning 中的 max 操作。

第二,dones的作用非常关键。当某个经验到达终止状态时,下一状态不存在真实的后续回报,TD 目标应该等于当前奖励,而不是加上下一状态的 Q 值。代码中用(1 - dones)把终止状态的期望回报置零。

第三,clip_grad_norm_做梯度裁剪,防止梯度值过大导致训练震荡。这在强化学习中是一个常用的稳定训练手段。

4.6 编写训练主循环

文件路径:train.py

训练主循环负责创建环境、创建智能体、交互采样、更新网络,并记录每个 episode 的回报,最后绘制奖励曲线。

import gymnasium as gym import matplotlib.pyplot as plt from replay_buffer import ReplayBuffer from dqn_agent import DQNAgent def train(episodes=400, batch_size=64, buffer_capacity=10000): env = gym.make("CartPole-v1") state_dim = env.observation_space.shape[0] action_dim = env.action_space.n agent = DQNAgent(state_dim, action_dim) replay_buffer = ReplayBuffer(buffer_capacity) reward_history = [] for episode in range(episodes): state, _ = env.reset() total_reward = 0 done = False while not done: action = agent.select_action(state) next_state, reward, terminated, truncated, _ = env.step(action) done = terminated or truncated replay_buffer.push(state, action, reward, next_state, done) agent.update(replay_buffer, batch_size) state = next_state total_reward += reward agent.update_epsilon() reward_history.append(total_reward) if (episode + 1) % 50 == 0: recent_avg = sum(reward_history[-50:]) / 50 print(f"Episode: {episode + 1}, Reward: {total_reward}, Avg(50): {recent_avg:.2f}, Epsilon: {agent.epsilon:.3f}") env.close() plt.plot(reward_history) plt.xlabel("Episode") plt.ylabel("Total Reward") plt.title("DQN Training Curve on CartPole") plt.show() if __name__ == "__main__": train()

这里需要说明一下 Gymnasium 的接口。新版环境在env.step()返回四个值:next_state、reward、terminated、truncated。terminated 表示因为达到终止条件而结束,比如杆掉落了;truncated 表示因为超过步数限制而结束,比如 CartPole 达到 500 步上限。这两种情况在 DQN 训练中都视为“本回合结束”,但严格来说只有 terminated 才表示真实终止。

CartPole 官方规定每步存活奖励为 1,达到 500 回合步数上限时会输出 truncated 为 True。在简单实现中,两者合并处理即可。

4.7 运行与验证

在项目目录中执行:

python train.py

运行时会输出类似下面的日志:

Episode: 50, Reward: 42, Avg(50): 52.10, Epsilon: 0.778 Episode: 100, Reward: 122, Avg(50): 95.36, Epsilon: 0.605 Episode: 150, Reward: 212, Avg(50): 146.28, Epsilon: 0.470 Episode: 200, Reward: 500, Avg(50): 284.55, Epsilon: 0.366 Episode: 250, Reward: 500, Avg(50): 476.12, Epsilon: 0.284

如果你的环境显示 CartPole 的最大分数是 500,说明训练效果已经达到环境上限。不同机器的训练速度不同,CPython 环境下几百个 episode 通常只需要几分钟。

如果希望更直观地观察智能体的表现,可以在训练结束后添加一段保存模型和推理演示的代码。保存模型最简单的做法是:

torch.save(agent.policy_net.state_dict(), "dqn_cartpole.pth")

加载的时候只需要恢复同样的网络结构:

model = DQN(state_dim, action_dim) model.load_state_dict(torch.load("dqn_cartpole.pth")) model.eval()

4.8 基于训练结果的分析

从训练曲线可以看到一个典型现象:在一开始,奖励值停留在很低的水平,因为 epsilon 很大,智能体频繁随机动作;随着训练推进,奖励开始波动上升;最后稳定在最大值附近。

这种波动是正常的,不需要因为某个 episode 分数下降就立刻怀疑代码有问题。DQN 的样本来自经验回放,网络更新是非平稳的,奖励曲线本身就会有较大噪声。评价训练效果应该看平移平均,而不是单次结果。

如果训练了很多轮后平均奖励仍然无法提升,大概率不是环境或代码“没跑起来”,而是某个关键参数不太合适,这在下一节会详细说明。

5. 常见问题与排查思路

在实际训练 DQN 的过程中,几乎每个人都会遇到下面几个问题。这里整理成表格,方便遇到类似报错或异常现象时快速定位。

问题现象常见原因解决思路
训练不收敛,奖励始终在低水平epsilon 衰减太慢或学习率太大增大 epsilon_decay 的衰减速度,减小 lr,尝试 lr=1e-4
训练前期很稳,后期突然崩掉目标网络更新太频繁或梯度爆炸增大 target_update,增加梯度裁剪或调低 lr
经验回放缓冲区占用内存过高capacity 设置过大调小容量,或改用数组实现减少 Python 对象开销
报错 env.reset() 返回太多值使用了旧版 gym 但代码按 Gymnasium 写改用obs = env.reset()的方式,或升级 gymnasium
报错 env.step() 返回值不匹配新旧版 API 差异新版返回 5 个值,旧版返回 4 个值,按版本调整
Q 值异常大,不断增长过高估计问题,DQN 的 max 操作导致换用 Double DQN 或用更小的学习率
训练曲线上下剧烈震荡样本批次大小太小、缓冲区容量太小增大 batch_size 和 buffer_capacity

除了表格里的内容,再补充几个常见细节。

第一,CartPole 的奖励恒为 1,累计奖励最大是 500。如果训练日志中 episode 的最大奖励已经是 500,不要误以为是代码 bug。这是评分上限。

第二,enp.step()返回的 reward 在 CartPole 里每一帧都是 1,所以“总奖励高”直接等价于“存活时间长”。但在其他环境中,这个对应关系不一定成立。

第三,如果使用旧版 gym 而不是 gymnasium,环境创建方式可能是gym.make("CartPole-v1"),但reset()返回的只有一个值,step()返回的是四元组。对老代码做兼容处理时,需要判断环境的 API 类型,或者干脆统一使用新版 gymnasium。

第四,关于“训练过程中 loss 不下降是不是正常”这个问题。强化学习中的 loss 不像普通监督学习那样单调下降,因为每一次更新的目标值也在变化。loss 本身不是判断训练好坏的唯一标准,更重要的是累积回报曲线和实际策略表现。

6. 最佳实践与工程建议

6.1 网络结构的选择

DQN 的网络结构并没有特别严格的规则。对于 CartPole 这类低维连续状态输入,两层 128 个神经元的全连接网络已经足够。不要一上来就堆大模型,更大的模型在网络容量足够之后并不会带来额外收益,反而容易引起训练不稳定。

对于图像输入,一般使用卷积神经网络,具体结构可以参考早期 DQN 论文中的设计,但输入输出维度需要根据实际环境调整。模型参数量的增加会直接拉长训练时间,经验回放缓冲区也会更快被填满。

6.2 超参数的配置建议

超参数是 DQN 训练最需要花时间的部分。基于常见实验经验,推荐从下面这组默认值开始:

  • 学习率:1e-3 到 1e-4。
  • 折扣因子:0.99。
  • 经验回放容量:10000 到 100000。
  • batch_size:32 到 128。
  • epsilon 初始值:1.0。
  • epsilon 最小值:0.01 到 0.05。
  • epsilon 衰减:按 episode 乘 0.99 到 0.995。
  • 目标网络更新频率:100 到 1000 步。

调试时每次只改一个超参数,观察效果后再调整下一个。如果同时改多个参数,很难判断是谁导致了变化。

6.3 训练过程的稳定性处理

稳定 DQN 训练的一个常用技巧是梯度裁剪。前面的代码中已经加入了clip_grad_norm_,这是一种简单有效的防爆炸手段。另一个常用技巧是学习率预热,即在前几百步使用较小的学习率,让网络先适应一下数据分布,再恢复正式学习率。

如果训练过程波动过大,可以尝试加大 batch_size。较大的 batch 能降低梯度估计方差,让更新方向更稳定。代价是训练变慢,内存占用变大。

6.4 实验记录与模型管理

强化学习实验的随机性很大,同一组参数在不同随机种子下跑的 reward 曲线可能差别明显。工程上建议:

  • 固定随机种子,确保实验可复现。
  • 记录每次实验的配置参数、代码版本、训练日志。
  • 不只保存最后一个模型的权重,也保存历史中表现最好的模型权重。
  • 用平均回报和最大回报两个指标同时评价模型。

固定随机种子可以在训练代码开头加上:

import random import numpy as np import torch random.seed(0) np.random.seed(0) torch.manual_seed(0)

这并不能完全消除所有不确定因素,但至少能让实验在相同软硬件环境下更接近可复现的状态。

6.5 安全与部署注意事项

把 DQN 模型部署到真实系统时,需要考虑几件事。首先,模型是离线训练出来的,它只见过训练环境,真实环境可能存在分布偏移,需要在部署前用小范围测试验证。其次,探索阶段的随机动作在真实系统中可能有安全风险,生产环境下通常要关闭探索,让模型直接采用贪心策略运行。最后,要保留人工干预的退路,不要让模型在失控情况下一直自动执行,这在机器人控制、工业自动化场景中尤为重要。

7. 总结与学习路线

这篇文章从 Q-Learning 表格法出发,梳理了 DQN 的核心动机和实现方式。关键点可以归纳为四条:神经网络替代表格来拟合 Q 函数;经验回放打破样本相关性;目标网络稳定训练目标;epsilon-greedy 平衡探索与利用。实战部分给出了一个可以直接运行的 CartPole DQN 代码,并解释了每一步的用途和潜在问题。

下一步的学习方向可以考虑:

  • Double DQN:解决 Q 值过高估计问题,把动作选择和 Q 值计算解耦。
  • Dueling DQN:把 Q 值拆成状态价值和动作优势,更细粒度地描述环境。
  • Prioritized Experience Replay:让重要经验更容易被采样到。
  • Rainbow DQN:把多种改进结合在一起,形成更完整的方法体系。

如果你已经能独立训练一个 CartPole DQN,这说明你已经跨过了 DQN 实现的门槛。接下来可以尝试更换环境,比如 LunarLander、FrozenLake,或者尝试用图像输入重新实现一遍,体验从低维状态到高维状态的接入过程。训练过程中遇到波动和失败是完全正常的,重要的是能够通过观察、分析、调整参数来定位问题。如果本文对你有帮助,可以收藏备用,下一篇可以继续深入 Double DQN 和 Dueling DQN 的对比实验。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询