微信登录

Q - learning 算法 - 深度 Q 网络 - DQN 的改进

TensorFlow 《Q - learning 算法 - 深度 Q 网络 - DQN 的改进》

一、引言

在强化学习领域,Q - learning 算法是一种经典的无模型算法,它通过估计状态 - 动作对的价值(Q 值)来指导智能体做出最优决策。然而,传统的 Q - learning 在处理高维状态空间时面临着严重的挑战,例如维度灾难。为了解决这一问题,深度 Q 网络(Deep Q - Network,DQN)应运而生,它结合了深度学习强大的特征提取能力和 Q - learning 的思想。但 DQN 本身也存在一些局限性,后续研究者们对其进行了一系列的改进。本文将详细介绍 Q - learning 算法、DQN 及其改进方法,并使用 TensorFlow 进行实现。

二、Q - learning 算法

2.1 基本原理

Q - learning 是一种基于价值的强化学习算法,其核心思想是通过迭代更新 Q 表来估计每个状态 - 动作对的最优动作价值。Q 表是一个二维表格,行表示状态,列表示动作,表格中的每个元素 $Q(s, a)$ 表示在状态 $s$ 下采取动作 $a$ 所能获得的期望累积奖励。

Q - learning 的更新公式如下:
[Q(st, a_t) \leftarrow Q(s_t, a_t) + \alpha [r{t+1} + \gamma \max{a} Q(s{t+1}, a) - Q(st, a_t)]]
其中,$\alpha$ 是学习率,控制每次更新的步长;$\gamma$ 是折扣因子,用于权衡当前奖励和未来奖励的重要性;$r
{t+1}$ 是在状态 $s_t$ 采取动作 $a_t$ 后获得的即时奖励。

2.2 代码实现(简单示例)

  1. import numpy as np
  2. # 定义状态和动作的数量
  3. num_states = 5
  4. num_actions = 2
  5. # 初始化 Q 表
  6. Q_table = np.zeros((num_states, num_actions))
  7. # 超参数
  8. alpha = 0.1
  9. gamma = 0.9
  10. episodes = 100
  11. for episode in range(episodes):
  12. # 初始化状态
  13. state = np.random.randint(0, num_states)
  14. done = False
  15. while not done:
  16. # 选择动作
  17. action = np.argmax(Q_table[state, :])
  18. # 模拟环境交互,获得下一个状态和奖励
  19. next_state = np.random.randint(0, num_states)
  20. reward = np.random.randint(0, 10)
  21. # 更新 Q 表
  22. Q_table[state, action] = Q_table[state, action] + alpha * (reward + gamma * np.max(Q_table[next_state, :]) - Q_table[state, action])
  23. state = next_state

三、深度 Q 网络(DQN)

3.1 基本原理

DQN 是为了解决传统 Q - learning 在高维状态空间中的问题而提出的。它使用一个深度神经网络来近似 Q 函数,将状态作为输入,输出每个动作的 Q 值。为了提高训练的稳定性,DQN 引入了两个重要的技术:经验回放和目标网络。

  • 经验回放:将智能体与环境交互的经验 $(st, a_t, r{t+1}, s_{t+1})$ 存储在一个经验回放缓冲区中,训练时随机从缓冲区中采样一批经验进行学习,这样可以打破数据之间的相关性,提高训练效率。
  • 目标网络:使用两个结构相同但参数不同的神经网络,一个用于生成动作(在线网络),另一个用于计算目标 Q 值(目标网络)。目标网络的参数定期从在线网络中复制,这样可以减少目标值的波动,提高训练的稳定性。

3.2 代码实现(使用 TensorFlow)

  1. import tensorflow as tf
  2. import numpy as np
  3. import random
  4. # 定义 DQN 网络
  5. class DQN(tf.keras.Model):
  6. def __init__(self, num_actions):
  7. super(DQN, self).__init__()
  8. self.dense1 = tf.keras.layers.Dense(64, activation='relu')
  9. self.dense2 = tf.keras.layers.Dense(64, activation='relu')
  10. self.output_layer = tf.keras.layers.Dense(num_actions)
  11. def call(self, x):
  12. x = self.dense1(x)
  13. x = self.dense2(x)
  14. return self.output_layer(x)
  15. # 超参数
  16. num_states = 4
  17. num_actions = 2
  18. gamma = 0.99
  19. epsilon = 0.1
  20. batch_size = 32
  21. memory_size = 1000
  22. target_update_freq = 10
  23. # 初始化网络和经验回放缓冲区
  24. online_network = DQN(num_actions)
  25. target_network = DQN(num_actions)
  26. target_network.set_weights(online_network.get_weights())
  27. memory = []
  28. # 定义优化器和损失函数
  29. optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
  30. loss_fn = tf.keras.losses.MeanSquaredError()
  31. # 训练函数
  32. def train():
  33. if len(memory) < batch_size:
  34. return
  35. batch = random.sample(memory, batch_size)
  36. states, actions, rewards, next_states, dones = zip(*batch)
  37. states = np.array(states, dtype=np.float32)
  38. actions = np.array(actions, dtype=np.int32)
  39. rewards = np.array(rewards, dtype=np.float32)
  40. next_states = np.array(next_states, dtype=np.float32)
  41. dones = np.array(dones, dtype=np.float32)
  42. with tf.GradientTape() as tape:
  43. q_values = online_network(states)
  44. action_masks = tf.one_hot(actions, num_actions)
  45. selected_q_values = tf.reduce_sum(action_masks * q_values, axis=1)
  46. next_q_values = target_network(next_states)
  47. max_next_q_values = tf.reduce_max(next_q_values, axis=1)
  48. target_q_values = rewards + (1 - dones) * gamma * max_next_q_values
  49. loss = loss_fn(target_q_values, selected_q_values)
  50. gradients = tape.gradient(loss, online_network.trainable_variables)
  51. optimizer.apply_gradients(zip(gradients, online_network.trainable_variables))
  52. # 训练循环
  53. episodes = 100
  54. for episode in range(episodes):
  55. state = np.random.rand(num_states)
  56. done = False
  57. while not done:
  58. if np.random.rand() < epsilon:
  59. action = np.random.randint(0, num_actions)
  60. else:
  61. q_values = online_network(np.expand_dims(state, axis=0))
  62. action = np.argmax(q_values)
  63. next_state = np.random.rand(num_states)
  64. reward = np.random.randint(0, 10)
  65. done = np.random.rand() < 0.1
  66. if len(memory) >= memory_size:
  67. memory.pop(0)
  68. memory.append((state, action, reward, next_state, done))
  69. train()
  70. state = next_state
  71. if episode % target_update_freq == 0:
  72. target_network.set_weights(online_network.get_weights())

四、DQN 的改进

4.1 双重 DQN(Double DQN)

传统 DQN 在选择目标动作时使用相同的网络来评估和选择动作,这可能会导致 Q 值的高估。双重 DQN 提出使用在线网络来选择动作,使用目标网络来评估动作的 Q 值,从而减少高估的问题。

  1. # 双重 DQN 训练函数
  2. def train_double_dqn():
  3. if len(memory) < batch_size:
  4. return
  5. batch = random.sample(memory, batch_size)
  6. states, actions, rewards, next_states, dones = zip(*batch)
  7. states = np.array(states, dtype=np.float32)
  8. actions = np.array(actions, dtype=np.int32)
  9. rewards = np.array(rewards, dtype=np.float32)
  10. next_states = np.array(next_states, dtype=np.float32)
  11. dones = np.array(dones, dtype=np.float32)
  12. with tf.GradientTape() as tape:
  13. q_values = online_network(states)
  14. action_masks = tf.one_hot(actions, num_actions)
  15. selected_q_values = tf.reduce_sum(action_masks * q_values, axis=1)
  16. next_online_q_values = online_network(next_states)
  17. next_actions = tf.argmax(next_online_q_values, axis=1)
  18. next_target_q_values = target_network(next_states)
  19. next_action_masks = tf.one_hot(next_actions, num_actions)
  20. max_next_q_values = tf.reduce_sum(next_action_masks * next_target_q_values, axis=1)
  21. target_q_values = rewards + (1 - dones) * gamma * max_next_q_values
  22. loss = loss_fn(target_q_values, selected_q_values)
  23. gradients = tape.gradient(loss, online_network.trainable_variables)
  24. optimizer.apply_gradients(zip(gradients, online_network.trainable_variables))

4.2 优先经验回放(Prioritized Experience Replay)

传统的经验回放是随机采样的,没有考虑不同经验的重要性。优先经验回放根据经验的时间差分误差(TD 误差)来给每个经验分配一个优先级,TD 误差越大,优先级越高,采样时更倾向于选择优先级高的经验,这样可以提高训练效率。

4.3 决斗 DQN(Dueling DQN)

决斗 DQN 将 Q 函数分解为状态价值函数 $V(s)$ 和优势函数 $A(s, a)$,即 $Q(s, a) = V(s) + A(s, a)$。通过这种分解,网络可以分别学习状态的价值和每个动作相对于其他动作的优势,从而提高学习效率。

  1. # 定义决斗 DQN 网络
  2. class DuelingDQN(tf.keras.Model):
  3. def __init__(self, num_actions):
  4. super(DuelingDQN, self).__init__()
  5. self.dense1 = tf.keras.layers.Dense(64, activation='relu')
  6. self.dense2 = tf.keras.layers.Dense(64, activation='relu')
  7. self.value_stream = tf.keras.layers.Dense(1)
  8. self.advantage_stream = tf.keras.layers.Dense(num_actions)
  9. def call(self, x):
  10. x = self.dense1(x)
  11. x = self.dense2(x)
  12. value = self.value_stream(x)
  13. advantage = self.advantage_stream(x)
  14. q_values = value + (advantage - tf.reduce_mean(advantage, axis=1, keepdims=True))
  15. return q_values

五、结论

Q - learning 算法是强化学习中的经典算法,DQN 通过引入深度神经网络和经验回放、目标网络等技术,解决了传统 Q - learning 在高维状态空间中的问题。然而,DQN 本身也存在一些局限性,双重 DQN、优先经验回放和决斗 DQN 等改进方法进一步提高了 DQN 的性能和稳定性。在实际应用中,可以根据具体问题选择合适的算法和改进方法。通过 TensorFlow 等深度学习框架,我们可以方便地实现这些算法,推动强化学习在各个领域的应用。

Q - learning 算法 - 深度 Q 网络 - DQN 的改进