理解和实现 Keras 架构下的 Dueling DQN
Dueling DQN(双重深度Q网络)是一种增强学习算法,它在学习的过程中将动作价值(Q-value)分解为状态价值和优势函数。这种结构能够有效提高智能体在复杂环境中的决策能力。
本文将指导你如何在Keras环境下实现Dueling DQN。我们将使用Python及Keras库来构建和训练我们的模型。
实现流程
在开始编写代码之前,首先要了解整个过程的步骤。以下是Dueling DQN实现的主要步骤:
步骤 | 描述 |
---|---|
1 | 导入必要的库 |
2 | 创建环境 |
3 | 定义神经网络架构 |
4 | 设定超参数 |
5 | 初始化经验回放存储器 |
6 | 训练DQN算法 |
7 | 测试模型 |
接下来,我们将逐步深入每一个细节。
第一步:导入必要的库
在开始之前,我们需要导入将要使用的库。
import numpy as np
import gym
from keras.models import Sequential
from keras.layers import Dense, Input
from keras.optimizers import Adam
from collections import deque
import random
代码说明
numpy
: 用于数值计算。gym
: OpenAI的强化学习环境库。keras.models
和keras.layers
: 用于构建深度学习模型。deque
: 提供一个双端队列,用于存储经验回放。random
: 用于实现随机选择。
第二步:创建环境
选择我们要使用的环境。这是通过gym
创建的。
env = gym.make('CartPole-v1')
代码说明
gym.make('CartPole-v1')
: 创建一个CartPole环境,目标是平衡一个杆子在移动的底座上。
第三步:定义神经网络架构
构建Dueling DQN的核心在于创建适当的神经网络架构。
def build_dueling_dqn(state_size, action_size):
# 创建模型
model = Sequential()
model.add(Input(shape=(state_size,)))
model.add(Dense(24, activation='relu'))
model.add(Dense(24, activation='relu'))
# 状态价值网络
value = Dense(1, activation='linear')(model.output)
# 优势网络
advantage = Dense(action_size, activation='linear')(model.output)
# 将值和优势结合
from keras.layers import Lambda
from keras import backend as K
def dueling_output(inputs):
advantage_output = K.expand_dims(inputs[1], axis=1) # 状态价值
value_output = inputs[0] # 优势
return value_output + (advantage_output - K.mean(advantage_output, axis=1, keepdims=True))
output = Lambda(dueling_output)([value, advantage])
model = Model(inputs=model.input, outputs=output)
model.compile(loss='mse', optimizer=Adam(lr=0.001))
return model
代码说明
build_dueling_dqn
: 创建Dueling DQN模型。Dense
: 全连接层。Lambda
: 构建自定义输出层以实现Dueling结构。K.mean()
: 用于计算优势函数的平均值,以便在输出中进行减法操作。
第四步:设定超参数
定义超参数是模型训练成功的关键。
state_size = env.observation_space.shape[0]
action_size = env.action_space.n
memory = deque(maxlen=2000) # 经验回放存储器
batch_size = 32
gamma = 0.95 # 折扣因子
epsilon = 1.0 # 初始epsilon值
epsilon_decay = 0.995
epsilon_min = 0.01
代码说明
state_size
和action_size
: 状态空间和动作空间的大小。memory
: 存储经验的队列。gamma
: 折扣因子,用于未来奖励的估计。epsilon
: 用于ε-greedy策略的阈值。epsilon_decay
: 每次训练后降低的epsilon值。epsilon_min
: epsilon的最小值。
第五步:初始化经验回放存储器
添加经验回放逻辑。
def remember(state, action, reward, next_state, done):
memory.append((state, action, reward, next_state, done))
代码说明
remember
: 将 (状态,动作,奖励,下一个状态,终止标志) 存储到经验回放中。
第六步:训练DQN算法
训练过程包括选择动作、存储经验、采样以及训练模型。
def train_dqn():
for e in range(EPISODES):
state = env.reset()
state = np.reshape(state, [1, state_size])
for time in range(500):
if np.random.rand() <= epsilon:
action = random.randrange(action_size)
else:
q_values = model.predict(state)
action = np.argmax(q_values[0])
next_state, reward, done, _ = env.step(action)
reward = reward if not done else -10
next_state = np.reshape(next_state, [1, state_size])
remember(state, action, reward, next_state, done)
state = next_state
if len(memory) > batch_size:
minibatch = random.sample(memory, batch_size)
for sample in minibatch:
s, a, r, s_next, d = sample
target = r
if not d:
target += gamma * np.amax(model.predict(s_next)[0])
target_f = model.predict(s)
target_f[0][a] = target
model.fit(s, target_f, epochs=1, verbose=0)
if done:
print(f"Episode: {e}/{EPISODES}, Score: {time}, Epsilon: {epsilon}")
break
if epsilon > epsilon_min:
epsilon *= epsilon_decay
代码说明
train_dqn
: 训练DQN的主函数。- 通过ε-greedy策略选择动作,存储经验,并进行训练。
第七步:测试模型
测试训练成功的模型表现。
for e in range(5):
state = env.reset()
state = np.reshape(state, [1, state_size])
for time in range(500):
env.render() # 可视化环境
q_values = model.predict(state)
action = np.argmax(q_values[0])
next_state, reward, done, _ = env.step(action)
next_state = np.reshape(next_state, [1, state_size])
state = next_state
if done:
print(f"Test Episode: {e}, Score: {time}")
break
代码说明
- 在测试过程中,我们通过可视化展示模型在环境中的表现。
结尾
通过以上步骤,你已经学会了如何实现Keras架构下的Dueling DQN。你可以根据需求进一步优化超参数和网络架构,以适应其他Gym环境或更多的复杂场景。希望你在强化学习的道路上越走越远!