
在强化学习领域,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 = 5num_actions = 2# 初始化 Q 表Q_table = np.zeros((num_states, num_actions))# 超参数alpha = 0.1gamma = 0.9episodes = 100for episode in range(episodes):# 初始化状态state = np.random.randint(0, num_states)done = Falsewhile 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 tfimport numpy as npimport 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 = 4num_actions = 2gamma = 0.99epsilon = 0.1batch_size = 32memory_size = 1000target_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:returnbatch = 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_valuesloss = 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 = 100for episode in range(episodes):state = np.random.rand(num_states)done = Falsewhile 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.1if len(memory) >= memory_size:memory.pop(0)memory.append((state, action, reward, next_state, done))train()state = next_stateif 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:returnbatch = 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_valuesloss = 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 等深度学习框架,我们可以方便地实现这些算法,推动强化学习在各个领域的应用。