在强化学习领域,Q - learning 算法是一种经典的无模型算法,它通过估计状态 - 动作对的价值(Q 值)来指导智能体做出最优决策。然而,传统的 Q - learning 在处理高维状态空间时面临着严重的挑战,例如维度灾难。为了解决这一问题,深度 Q 网络(Deep Q - Network,DQN)应运而生,它结合了深度学习强大的特征提取能力和 Q - learning 的思想。但 DQN 本身也存在一些局限性,后续研究者们对其进行了一系列的改进。本文将详细介绍 Q - learning 算法、DQN 及其改进方法,并使用 TensorFlow 进行实现。
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$ 后获得的即时奖励。
import numpy as np
# 定义状态和动作的数量
num_states = 5
num_actions = 2
# 初始化 Q 表
Q_table = np.zeros((num_states, num_actions))
# 超参数
alpha = 0.1
gamma = 0.9
episodes = 100
for episode in range(episodes):
# 初始化状态
state = np.random.randint(0, num_states)
done = False
while not done:
# 选择动作
action = np.argmax(Q_table[state, :])
# 模拟环境交互,获得下一个状态和奖励
next_state = np.random.randint(0, num_states)
reward = np.random.randint(0, 10)
# 更新 Q 表
Q_table[state, action] = Q_table[state, action] + alpha * (reward + gamma * np.max(Q_table[next_state, :]) - Q_table[state, action])
state = next_state
DQN 是为了解决传统 Q - learning 在高维状态空间中的问题而提出的。它使用一个深度神经网络来近似 Q 函数,将状态作为输入,输出每个动作的 Q 值。为了提高训练的稳定性,DQN 引入了两个重要的技术:经验回放和目标网络。
import tensorflow as tf
import numpy as np
import random
# 定义 DQN 网络
class DQN(tf.keras.Model):
def __init__(self, num_actions):
super(DQN, self).__init__()
self.dense1 = tf.keras.layers.Dense(64, activation='relu')
self.dense2 = tf.keras.layers.Dense(64, activation='relu')
self.output_layer = tf.keras.layers.Dense(num_actions)
def call(self, x):
x = self.dense1(x)
x = self.dense2(x)
return self.output_layer(x)
# 超参数
num_states = 4
num_actions = 2
gamma = 0.99
epsilon = 0.1
batch_size = 32
memory_size = 1000
target_update_freq = 10
# 初始化网络和经验回放缓冲区
online_network = DQN(num_actions)
target_network = DQN(num_actions)
target_network.set_weights(online_network.get_weights())
memory = []
# 定义优化器和损失函数
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
loss_fn = tf.keras.losses.MeanSquaredError()
# 训练函数
def train():
if len(memory) < batch_size:
return
batch = random.sample(memory, batch_size)
states, actions, rewards, next_states, dones = zip(*batch)
states = np.array(states, dtype=np.float32)
actions = np.array(actions, dtype=np.int32)
rewards = np.array(rewards, dtype=np.float32)
next_states = np.array(next_states, dtype=np.float32)
dones = np.array(dones, dtype=np.float32)
with tf.GradientTape() as tape:
q_values = online_network(states)
action_masks = tf.one_hot(actions, num_actions)
selected_q_values = tf.reduce_sum(action_masks * q_values, axis=1)
next_q_values = target_network(next_states)
max_next_q_values = tf.reduce_max(next_q_values, axis=1)
target_q_values = rewards + (1 - dones) * gamma * max_next_q_values
loss = loss_fn(target_q_values, selected_q_values)
gradients = tape.gradient(loss, online_network.trainable_variables)
optimizer.apply_gradients(zip(gradients, online_network.trainable_variables))
# 训练循环
episodes = 100
for episode in range(episodes):
state = np.random.rand(num_states)
done = False
while not done:
if np.random.rand() < epsilon:
action = np.random.randint(0, num_actions)
else:
q_values = online_network(np.expand_dims(state, axis=0))
action = np.argmax(q_values)
next_state = np.random.rand(num_states)
reward = np.random.randint(0, 10)
done = np.random.rand() < 0.1
if len(memory) >= memory_size:
memory.pop(0)
memory.append((state, action, reward, next_state, done))
train()
state = next_state
if episode % target_update_freq == 0:
target_network.set_weights(online_network.get_weights())
传统 DQN 在选择目标动作时使用相同的网络来评估和选择动作,这可能会导致 Q 值的高估。双重 DQN 提出使用在线网络来选择动作,使用目标网络来评估动作的 Q 值,从而减少高估的问题。
# 双重 DQN 训练函数
def train_double_dqn():
if len(memory) < batch_size:
return
batch = random.sample(memory, batch_size)
states, actions, rewards, next_states, dones = zip(*batch)
states = np.array(states, dtype=np.float32)
actions = np.array(actions, dtype=np.int32)
rewards = np.array(rewards, dtype=np.float32)
next_states = np.array(next_states, dtype=np.float32)
dones = np.array(dones, dtype=np.float32)
with tf.GradientTape() as tape:
q_values = online_network(states)
action_masks = tf.one_hot(actions, num_actions)
selected_q_values = tf.reduce_sum(action_masks * q_values, axis=1)
next_online_q_values = online_network(next_states)
next_actions = tf.argmax(next_online_q_values, axis=1)
next_target_q_values = target_network(next_states)
next_action_masks = tf.one_hot(next_actions, num_actions)
max_next_q_values = tf.reduce_sum(next_action_masks * next_target_q_values, axis=1)
target_q_values = rewards + (1 - dones) * gamma * max_next_q_values
loss = loss_fn(target_q_values, selected_q_values)
gradients = tape.gradient(loss, online_network.trainable_variables)
optimizer.apply_gradients(zip(gradients, online_network.trainable_variables))
传统的经验回放是随机采样的,没有考虑不同经验的重要性。优先经验回放根据经验的时间差分误差(TD 误差)来给每个经验分配一个优先级,TD 误差越大,优先级越高,采样时更倾向于选择优先级高的经验,这样可以提高训练效率。
决斗 DQN 将 Q 函数分解为状态价值函数 $V(s)$ 和优势函数 $A(s, a)$,即 $Q(s, a) = V(s) + A(s, a)$。通过这种分解,网络可以分别学习状态的价值和每个动作相对于其他动作的优势,从而提高学习效率。
# 定义决斗 DQN 网络
class DuelingDQN(tf.keras.Model):
def __init__(self, num_actions):
super(DuelingDQN, self).__init__()
self.dense1 = tf.keras.layers.Dense(64, activation='relu')
self.dense2 = tf.keras.layers.Dense(64, activation='relu')
self.value_stream = tf.keras.layers.Dense(1)
self.advantage_stream = tf.keras.layers.Dense(num_actions)
def call(self, x):
x = self.dense1(x)
x = self.dense2(x)
value = self.value_stream(x)
advantage = self.advantage_stream(x)
q_values = value + (advantage - tf.reduce_mean(advantage, axis=1, keepdims=True))
return q_values
Q - learning 算法是强化学习中的经典算法,DQN 通过引入深度神经网络和经验回放、目标网络等技术,解决了传统 Q - learning 在高维状态空间中的问题。然而,DQN 本身也存在一些局限性,双重 DQN、优先经验回放和决斗 DQN 等改进方法进一步提高了 DQN 的性能和稳定性。在实际应用中,可以根据具体问题选择合适的算法和改进方法。通过 TensorFlow 等深度学习框架,我们可以方便地实现这些算法,推动强化学习在各个领域的应用。