【RL】DQN的简单实现

160次阅读
没有评论

共计 3982 个字符,预计需要花费 10 分钟才能阅读完成。

本文将实现一个简单的 DQN(Deep Q-Network)Agent。DQN 是深度强化学习中的一个经典算法,用于学习从环境状态到动作的映射,使得 Agent 能够在环境中做出正确的决策以获得最大的奖励。

Q-Learning 简述

首先来对 QLearning 进行简单的解释。

Q-learning 是一种基于值迭代的强化学习算法,用于学习在给定环境中的最优策略。它的核心思想是通过更新 Q 值函数来学习如何在每个状态下选择最优动作,以最大化累积奖励。下面详细解释 Q -learning 算法及其数学公式:

  1. 算法描述:
    假设我们有一个由状态空间 S 和动作空间 A 组成的 MDP(马尔可夫决策过程)。Q-learning 算法使用一个 Q 值函数 Q(s, a) 来表示在状态 s 下采取动作 a 所能获得的累积奖励。该算法的主要步骤如下:
  • 初始化 Q 值函数 Q(s, a) 为任意初始值,对所有状态 - 动作对(s, a);
  • 不断与环境交互,从当前状态 s 开始,采取动作 a,得到奖励 r 和下一个状态 s ’;
  • 更新 Q 值函数:Q(s, a) = Q(s, a) + α [r + γ max(Q(s’, a’)) – Q(s, a)],其中 α 是学习率,γ 是折扣因子;
  • 将当前状态更新为下一个状态:s = s’;
  • 重复以上步骤直到收敛或达到预定迭代次数。
  1. 数学公式:
    Q-learning 算法的核心更新规则由以下数学公式表示:

Q(s, a) = Q(s, a) + α [r + γ max(Q(s’, a’)) – Q(s, a)]

其中,

  • Q(s, a) 表示在状态 s 下采取动作 a 所能获得的累积奖励(Q 值);
  • α(0 ≤ α ≤ 1)是学习率,控制更新的步长,用于平衡新旧 Q 值的权重;
  • r 是在当前状态 s 下采取动作 a 后获得的即时奖励;
  • γ(0 ≤ γ ≤ 1)是折扣因子,用于权衡当前奖励和未来奖励的重要性;
  • max(Q(s’, a’)) 是在下一个状态 s ’ 下所有可能动作 a ’ 的 Q 值的最大值。

更新公式表示了一个基于差分的更新过程,将当前的 Q 值逐步调整,使其逼近目标 Q 值,即即时奖励与下一状态的最大 Q 值的组合。

在 Q -learning 算法中,Agent 通过不断与环境交互和更新 Q 值函数来学习最优策略。在学习过程中,Agent 逐渐探索并学习到在每个状态下采取最优动作,从而使得累积奖励最大化。经过足够的迭代和训练,Q 值函数将收敛到最优值,从而找到最优的策略。

而 DQN 就是用神经网络来拟合 Q 函数。

DQN 实现

让我们逐步解释代码中的每个部分:

  1. 导入模块:
import time
import numpy as np
import tensorflow as tf
from collections import deque
import random
from tensorflow.keras.layers import Convolution2D, Flatten
from tensorflow.keras.layers import Dense

在这里,代码导入了一些必要的库和模块,包括时间处理、数组操作、TensorFlow 框架、双端队列(deque)、随机数生成和 Keras 中的一些层。

  1. DQNAgent 类:
class DQNAgent:
def __init__(self, state_size, action_size):
# ...
# 初始化一些参数和变量
# ...
self.model = self._build_model() # 创建 DQN 模型
def _build_model(self):
# ...
# 创建 DQN 模型的结构并编译
# ...
def remember(self, state, action, reward, next_state, done):
# ...
# 存储经验回放的方法
# ...
def act(self, state, use_model=False):
# ...
# 根据当前状态选择动作的方法
# ...
def replay(self, batch_size):
# ...
# 更新神经网络的方法
# ...
  1. 初始化方法:
def __init__(self, state_size, action_size):
self.state_size = state_size
self.action_size = action_size
self.memory = deque(maxlen=2000) # 用于存储经验回放的经验存储器
self.gamma = 0.95 # 折扣因子
self.epsilon = 0.95 # 探索因子
self.epsilon_decay = 0.995 # 探索因子的衰减率
self.epsilon_min = 0.01 # 探索因子的最小值
self.learning_rate = 0.0001 # 学习率
self.model = self._build_model()

这是 DQNAgent 类的初始化方法。它设置了 Agent 的初始状态,包括状态空间大小(state_size)、动作空间大小(action_size)、经验回放存储器(memory)、折扣因子(gamma,用于考虑未来奖励的重要性)、探索因子(epsilon,用于控制随机探索的概率)、探索因子的衰减率(epsilon_decay,探索因子随时间逐渐减小)、探索因子的最小值(epsilon_min,最小探索概率)和学习率(learning_rate,用于更新神经网络的参数)。

  1. 构建 DQN 模型的方法:
def _build_model(self):
model = tf.keras.Sequential()
model.add(Convolution2D(32, 8, (4, 4), activation='relu',
input_shape=self.state_size))
model.add(Convolution2D(64, 4, (2, 2), activation='relu'))
model.add(Convolution2D(64, 3, (1, 1), activation='relu'))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dense(self.action_size))
model.compile(loss='mse', optimizer=tf.keras.optimizers.Adam(lr=self.learning_rate))
return model

这个方法定义了 DQN 模型的结构,使用了卷积层和全连接层构建神经网络。输入是环境状态(state),输出是动作空间的 Q 值。这个方法还编译了模型,指定了均方误差(MSE)作为损失函数,并使用 Adam 优化器进行参数更新。

  1. 存储经验回放的方法:
def remember(self, state, action, reward, next_state, done):
self.memory.append((state, action, reward, next_state, done))

这个方法用于将 Agent 在环境中的经验(状态、动作、奖励、下一个状态和完成标志)存储到经验回放存储器中。经验回放是 DQN 算法中的一项重要技术,用于从存储的经验中随机抽取一批数据来进行训练,以减少数据之间的相关性。

  1. 根据当前状态选择动作的方法:
def act(self, state, use_model=False):
if not use_model:
print("Using random action.")
if np.random.rand() <= self.epsilon:
time.sleep(0.1)
return random.randrange(self.action_size)
q_values = self.model.predict(state)
return np.argmax(q_values[0])

这个方法根据当前状态(state)选择一个动作(action)。如果 use_model 为 False,那么 Agent 会以一定的概率(由 epsilon 控制)随机选择动作,以进行探索。如果 use_model 为 True,那么 Agent 将根据当前模型预测的 Q 值选择最优的动作。

  1. 更新神经网络的方法:
def replay(self, batch_size):
minibatch = random.sample(self.memory, batch_size)
for state, action, reward, next_state, done in minibatch:
target = reward
if not done:
target = (reward + self.gamma * np.amax(self.model.predict(next_state)[0]))
target_f = self.model.predict(state)
target_f[0][action] = target
self.model.fit(state, target_f, epochs=1, verbose=0)
if self.epsilon > self.epsilon_min:
self.epsilon *= self.epsilon_decay

读到这你可能有疑问,DQN 不是应该有两个网络吗?DQN 中的两个网络具有相同网络结构,只是参数不同。这里其实就是用上一次更新的模型来预测,然后进行一步更新。因此这里其实是其他 DQN 实现中把两个网络复制更新的步长设为 1。

这个方法用于更新神经网络的参数,以减小预测值与目标值之间的差距。首先,从经验回放存储器中随机采样一个批次的经验(minibatch)。

然后,对于每个经验,计算目标 Q 值。如果游戏没有结束(done 为 False),目标 Q 值是当前奖励加上折扣因子乘以下一个状态的最大 Q 值;如果游戏结束(done 为 True),目标 Q 值就是当前奖励。接着,根据目标 Q 值和当前状态,更新模型的参数。最后,如果当前探索因子大于最小探索因子,就按照衰减率逐渐减小探索因子。

正文完
 0
评论(没有评论)