0. 前言
在《强化学习基础》一节中,我们学习了强化学习的基本概念,并且介绍了如何在给定状态下采取随机动作。此外,我们还使用自定义环境,计算下一个状态、动作和奖励。在本节中,我们首先介绍 Q 学习与深度 Q 学习的基本思想,然后利用 OpenAI
的 Gym
库模拟 Frozen Lake
和 CartPole
问题,并使用 Keras
实现 Q 学习解决这两个问题。
1. Q 学习简介
状态-动作值函数 (State-Action Value Function
),简称 Q 函数,定义为从状态 s t s_t st 同时执行动作 a t a_t at 的双重设定下,在策略 π π π 的控制下能获得的期望回报值:
Q π ( s t , a t ) = E τ ∼ p ( τ ) [ R ( τ t : T ) ∣ τ a t = a t , τ s t = s t ] Q^π(s_t, a_t) = E_{τ∼p(τ)}[R(τ_{t:T})|τ_{a_t} = a_t , τ_{s_t}= s_t ] Qπ(st,at)=Eτ∼p(τ)[R(τt:T)∣τat=at,τst=st]
在最优策略 π ∗ ( a ∣ s ) π^*(a|s) π∗(a∣s) 下,具有以下关系:
Q ∗ ( s t , a t ) = m a x π Q π ( s t , a t ) π ∗ = a r g m a x a t Q ∗ ( s t , a t ) Q∗(st,at)=maxπQπ(st,at)π∗=argmaxatQ∗(st,at) Q∗(st,at)=πmaxQπ(st,at)π∗=atargmaxQ∗(st,at)
Q 学习 (Q Learning
) 算法通过下式估计 Q ∗ ( s t , a t ) Q^*(s_t, a_t) Q∗(st,at) 函数,并利用 π ε ( s t ) \pi^{\varepsilon}(s_t) πε(st) 策略来获得策略改进:
Q ∗ ( s t , a t ) ← Q ∗ ( s t , a t ) + α ( r ( s t , a t ) + γ m a x a t + 1 Q ∗ ( s t + 1 , a t + 1 ) − Q ∗ ( s t , a t ) ) Q^*(s_t, a_t)\larr Q^*(s_t, a_t)+\alpha(r(s_t,a_t)+\gamma\underset{a_{t+1}}{max}Q^*(s_{t+1},a_{t+1})-Q^*(s_t, a_t)) Q∗(st,at)←Q∗(st,at)+α(r(st,at)+γat+1maxQ∗(st+1,at+1)−Q∗(st,at))
深度 Q 网络 (Deep Q Network
, DQN
) 用深层的神经网络来参数化 Q ∗ ( s t , a t ) Q^*(s_t, a_t) Q∗(st,at) 函数,并利用梯度下降算法循环更新 Q 网络。
2. 使用 Q 学习进行 FrozenLake 游戏
2.1 FrozenLake 环境分析
FrozenLake
环境如下所示:
智能体从状态 S
开始,目标是通过尽可能避免状态 H
来达到状态 G
,智能体可以处于 16
种可能的状态。此外,智能体可以采取四种可能的动作(向上,向下,向右或向左移动)。
我们将定义一个 q-表
,其中有 16
行对应于 16
个状态,四列对应于在每种状态下可以采取的四个动作:
- 在当前状态下采取动作的值=在当前状态下采取动作的值+ 1*(奖励+折扣系数*在下一个状态下采取的最佳动作的值-在当前状态下采取动作的值)
我们将学习率设为 1
,以使状态下某个动作的值更新不会急剧变化:
- 在当前状态下采取动作的值=在当前状态下采取动作的值+学习率*(奖励+折扣系数*下一种状态采取的最佳可能行动的值-在当前状态下采取动作的值)
根据以上公式更新 q-表
,以便确定在不同状态下可以采取的最佳动作。
2.2 模型分析
在实际解决问题之前,我们将首先探讨用于解决 FrozenLake
问题的模型策略:
- 使用
OpenAI的Gym
实例化FrozenLake
环境 - 初始化形状为
16 x 4
的q-表
,其中所有元素值为0
- 在给定状态下选择动作时,采用探索-利用法:
- 在早期迭代中探索,因为我们不确定在游戏的最初几个回合中应采取的最佳动作。
- 但是,随着我们对游戏的了解越来越多,我们在采取可能的最佳动作的同时,仍然采取一定概率的随机行动(随着回合的增加,概率逐渐降低)来利用所学到的知识
- 在给定的回合中:
- 根据我们是否尝试探索或利用来选择动作
- 确定新的状态和奖励,并通过执行上一步中选择的动作来检查游戏是否结束
- 初始化学习率参数和折扣因子
- 通过使用上述公式来更新在
q-表
中的状态下采取所选动作的值 - 重复上述步骤,直到游戏结束
- 重复进行
1000
回合以上游戏 - 检查
q-表
以识别在给定状态下要采取的最佳动作 - 绘制智能体的路径,以使其根据
q-表
在状态下执行动作
2.3 使用 Q 学习算法解决 FrozenLake 问题
(1) 导入 Gym
以及其他相关库,Gym
是用于开发和比较强化学习算法的工具包,它支持多种模拟环境,关于 Gym
更多介绍,可以参考《强化学习环境配置》:
import gym
from gym.envs.registration import register
import random
(2) 注册并创建环境,为了简化游戏,我们修改了 FrozenLake
环境的默认设定,最重要的设置是令冰面并不滑,每一步动作的结果都是确定,而冰面滑时,即时指定向左的动作,智能体也可能会滑动到其他位置,例如向下滑:
register(
id = 'FrozenLakeNotSlippery-v1',
entry_point = 'gym.envs.toy_text:FrozenLakeEnv',
kwargs = {
'map_name': '4x4', 'is_slippery': False},
max_episode_steps = 100,
reward_threshold = 0.8196
)
env = gym.make('FrozenLakeNotSlippery-v1')
(3) 检查创建的环境,reset()
方法用于重置游戏环境:
env.reset()
env.render()
渲染出的 FrozenLake
环境如下:
(4) 我们也可以检查环境中状态空间与动作空间数量,由于我们使用的 FrozenLake
环境包括 4 x 4
的网格,共有 16
个状态。因此,共有 16
个观测值:
print(env.observation_space)
print(env.action_space.n)
输出结果如下所示:
Discrete(16)
4
(5) 接下来,从动作空间中采样一个动作,并使用 step()
方法采取该动作,以生成新状态、奖励、是否完成游戏的标记以及有关该步骤的其他信息:
action = env.action_space.sample()
new_state, reward, is_done, info = env.step(action)
(6) 初始化 q-表
,因为有 16
种状态,每种状态有 4
种可能的动作,因此 q-表
的形状为 (16, 4)
:
import numpy as np
qtable = np.zeros((16,4))
(7) 初始化超参数后,运行 FrozenLake
游戏多个回合:
total_episodes=15000
learning_rate=0.8
max_steps=99
gamma=0.95
epsilon=1
max_epsilon=1
min_epsilon=0.01
decay_rate=0.005
rewards=[]
for episode in range(total_episodes):
state=env.reset()
step=0
done=False
total_rewards=0
(8) 定义要采取的策略。如果 eps
(一个介于 0
到 1
之间的随机数)小于 0.5
,我们将进行探索;否则,我们会进行利用(考虑 q-表
中的最佳操作):
rewards=[]
for episode in range(total_episodes):
state=env.reset()
step=0
done=False
total_rewards=0
for step in range(max_steps):
exp_exp_tradeoff=random.uniform(0,1)
# Exploitation:
if exp_exp_tradeoff>epsilon:
action=np.argmax(qtable[state,:])
else:
# Exploration
action=env.action_space.sample()
(9) 获取新状态和奖励,并通过在给定步骤中采取动作获取游戏是否完成:
new_state,reward,done,info=env.step(action)
(10) 基于当前状态状态执行的操作更新 q-表
,并使用在当前状态下执行动作后获得的新状态来更新状态:
# Update the Q
qtable[state,action]=qtable[state,action]+\
learning_rate*(reward+gamma*np.max(qtable[new_state,:])-qtable[state,action])
total_rewards+=reward
state=new_state
(11) 当本次游戏回合结束后,我们继续进行下一个新的游戏回合,同时,我们更新用于决定要进行探索还是利用的随机因子 (eps
):
if done:
break
episode+=1
epsilon=min_epsilon+(max_epsilon-min_epsilon)*np.exp(decay_rate*episode)
rewards.append(total_rewards)
(12) 一旦建立了 q-表
,我们就可以根据 q-表
得到的最佳动作指导智能体以进行动作:
print("Score over Time:",sum(rewards)/total_episodes)
print(qtable)
打印出的 q-表
如下所示:
[[0.73509189 0.77378094 0.77378094 0.73509189]
[0.73509189 0. 0.81450625 0.77378094]
[0.77378094 0.857375 0.77378094 0.81450625]
[0.81450625 0. 0.77378094 0.77378094]
[0.77378094 0.81450625 0. 0.73509189]
[0. 0. 0. 0. ]
[0. 0.9025 0. 0.81450625]
[0. 0. 0. 0. ]
[0.81450625 0. 0.857375 0.77378094]
[0.81450625 0.9025 0.9025 0. ]
[0.857375 0.95 0. 0.857375 ]
[0. 0. 0. 0. ]
[0. 0. 0. 0. ]
[0. 0.9025 0.95 0.857375 ]
[0.9025 0.95 1. 0.9025 ]
[0. 0. 0. 0. ]]
(13) 继续使用一个新回合,使用得到的 q-表
计算智能体到达最终目标经过的最佳路径:
env.reset()
for episode in range(1):
state=env.reset()
step=0
done=False
print("-----------------------")
print("Episode",episode)
for step in range(max_steps):
env.render()
action=np.argmax(qtable[state,:])
print(action)
new_state,reward,done,info=env.step(action)
if done:
env.render()
print("Number of Steps",step+1)
break
state=new_state
env.close()
得到的最佳路径如下所示:
Episode 0
SFFF
FHFH
FFFH
HFFG
1
(Down)
...
2
(Right)
SFFF
FHFH
FFFH
HFFG
Number of Steps 6
除此之外,我们也可以使用冰面较滑的环境进行相同的实验。
3. 使用深度 Q 学习进行 CartPole 游戏
在前面的部分中,我们学习了基于 q-表
值执行动作的方法。但是,达到最佳值需要耗费大量时间,因为智能体必须通过进行多次游戏才能得到最佳 q-表
。接下来,我们将学习如何使用神经网络,以便比使用 q-表
时更快地达到最佳值。
3.1 问题分析
在本节中,我们将使用 CartPole
环境,其中智能体可能的动作包括向右或向左移动推车,以便平衡推车上的杆。此外,环境中的状态信息包括推车位置,推车速度,杆与推车的夹角和杆顶端处的速度。关于 CartPole
环境更详细的说明可以参考官方网页或《强化学习环境配置》。
在 CartPole
环境中,杆通过一个未固定的接头连接到小推车,小推车沿着无摩擦的轨道移动。该系统通过向推车施加 +1
或 -1
的力来控制推车移动。杆开始时垂直于推车,智能体的目标是防止杆跌落。杆保持直立的每个时间戳都可以得到 +1
的奖励。当杆与垂直方向的夹角超过 15
度或推车距离中心点超过 2.4
个单位以上时,回合结束。
3.2 模型分析
为了保持杆的平衡,我们使用深度 Q 学习算法,利用神经网络来预测智能体需要采取的最佳动作,训练神经网络的策略如下:
- 存储有关状态值、采取动作和获得奖励的信息:
- 如果游戏未结束,则奖励为
1
,否则为0
- 如果游戏未结束,则奖励为
- 开始时,神经网络基于随机初始化的权重进行预测,模型的输出层具有两个节点,对应于两个可能动作的新状态值
- 新状态值基于最大化新状态值的动作
- 如果游戏没有结束,使用奖励和新状态的最大状态值与折扣因子之积来更新当前状态值
- 从先前获得的更新后的当前状态值中覆盖动作的值:
- 如果当前步骤中执行的动作导致游戏结束,则当前状态下的动作值为
0
- 否则,当前步骤中的值是一个正数
- 令模型找出要采取的正确动作
- 如果当前步骤中执行的动作导致游戏结束,则当前状态下的动作值为
- 另外,可以使用这种方法来指定奖励为
0
时动作是错误的;但是,由于不确定在奖励为1
时是否是正确的动作,因此仅针对执行的动作对其进行更新,并保持新状态的值不变 - 将状态值追加到输入数组,以及在当前状态下采取动作的值作为输出数组
- 对模型进行拟合,以使数据样本的均方误差最小
- 最后,随着回合数的增加不断减少探索
3.3 使用深度 Q 学习算法解决 CartPole 问题
(1) 导入所需库,创建 CartPole
环境并存储动作空间大小和状态空间大小:
import gym
import numpy as np
import random
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import Adam
from collections import deque
env = gym.make('CartPole-v0')
state_size = env.observation_space.shape[0]
action_size = env.action_space.n
CartPole
环境如下所示:
(2) 构建并编译神经网络模型:
model=Sequential()
model.add(Dense(24,input_dim=state_size,activation='relu'))
model.add(Dense(24,activation='relu'))
model.add(Dense(2,activation='linear'))
model.compile(loss='mse',optimizer=Adam(lr=0.01))
(3) 初始化超参数以及所需列表:
memory = deque(maxlen=2000)
gamma = 0.95 # discount rate
epsilon = 1.0 # exploration rate
epsilon_min = 0.01
epsilon_decay = 0.995
done = False
batch_size=32
(4) 定义函数,该函数接受神经网络模型,批大小和 epsilon
(用于确定探索还是利用)作为参数。首先,获取 batch_size
大小的随机样本,其中 memory
包括状态 (state
)、动作 (action
)、奖励 (reward
) 和新状态 (next_state
) 等。如果游戏未结束,更新所采取动作的奖励;否则,奖励为 0
。此外,模型可以预测采取某项动作的值(因为该模型在输出中有 2
个节点——每个节点都提供对采取某一动作的输出)。函数返回更新的模型和探索/利用系数 (epsilon
):
def replay(model, batch_size,epsilon):
epsilon_min = 0.01
epsilon_decay = 0.995
minibatch = random.sample(memory, batch_size)
for state, action, reward, next_state, done in minibatch:
target = reward
if not done:
target = (reward + gamma *np.amax(model.predict(next_state)[0]))
new_action_value = model.predict(state)
new_action_value[0][action] = target
model.fit(state,new_action_value, epochs=1, verbose=0)
if epsilon > epsilon_min:
epsilon *= epsilon_decay
return model,epsilon
(5) 进行 CartPole
游戏多个回合,并记录智能体获得的分数。此外,确保模型根据 epsilon
值指示智能体采取的动作:
episodes=200
maxsteps=200
score_list = []
for e in range(episodes):
state = env.reset()
state = np.reshape(state, [1, state_size])
在以上代码中,共进行 200
个回合 CartPole
游戏,在每次回合开始时重置环境,我们还需要整形状态 state
,以便可以将其传递给神经网络模型。
(6) 接下来,我们将基于探索参数 (epsilon
) 采取行动,大约有 epsilon
的概率会采取随机动作 (env.actionspace.sample()
),在其他情况下,会利用模型的预测采取相应动作:
for step in range(maxsteps):
if np.random.rand()<=epsilon:
action=env.action_space.sample()
else:
action = np.argmax(model.predict(state)[0])
(7) 接下来,在每个时间戳执行一个动作并获取下一个状态、奖励以及有关游戏是否结束的信息。如果游戏结束,使用 -10
作为奖励值,表明执行了不正确的动作。此外,提取下一个状态并将其添加到 memory
中。这样,就为要训练的模型创建了一个数据集,该模型采用当前状态和奖励来计算两个可能动作的奖励:
next_state, reward, done, _ = env.step(action)
reward = reward if not done else -10
next_state = np.reshape(next_state, [1, state_size])
memory.append((state, action, reward, next_state, done))
(8) 如果游戏结束,我们将记录得分(游戏过程中的时间戳数);否则,将更新模型。此外,仅当 memory
中的数据样本数与大于预定义的批大小时,才会更新模型:
state = next_state
if done:
print("episode: {}/{}, score: {}, exp prob: {:.2}".format(e, episodes, step, epsilon))
score_list.append(step)
break
if len(memory) > batch_size:
model,epsilon=replay(model, batch_size,epsilon)
(9) 绘制随着时间的增加,每个回合的得分情况:
import matplotlib.pyplot as plt
plt.plot(range(1,len(score_list)+1),score_list)
plt.title('Game score over increasing episodes')
plt.show()
小结
强化学习使用马尔可夫决策过程的形式化框架,使用状态、动作和奖励定义学习型智能体与环境的交互过程。Q 学习作为一种经典的强化学习算法,可以直接优化一个可迭代计算的 Q 函数,能够比较可用动作的预期效用,而不需要环境模型。在本节中,我们首先介绍 Q 学习与深度 Q 学习的基本思想,并使用 Keras
实现 Q 学习解决 Frozen Lake
和 CartPole
问题。
系列链接
Keras深度学习实战(1)——神经网络基础与模型训练过程详解
Keras深度学习实战(2)——使用Keras构建神经网络
Keras深度学习实战(3)——神经网络性能优化技术
Keras深度学习实战(4)——深度学习中常用激活函数和损失函数详解
Keras深度学习实战(5)——批归一化详解
Keras深度学习实战(6)——深度学习过拟合问题及解决方法
Keras深度学习实战(7)——卷积神经网络详解与实现
Keras深度学习实战(8)——使用数据增强提高神经网络性能
Keras深度学习实战(9)——卷积神经网络的局限性
Keras深度学习实战(10)——迁移学习详解
Keras深度学习实战(11)——可视化神经网络中间层输出
Keras深度学习实战(12)——面部特征点检测
Keras深度学习实战(13)——目标检测基础详解
Keras深度学习实战(14)——从零开始实现R-CNN目标检测
Keras深度学习实战(15)——从零开始实现YOLO目标检测
Keras深度学习实战(16)——自编码器详解
Keras深度学习实战(17)——使用U-Net架构进行图像分割
Keras深度学习实战(18)——语义分割详解
Keras深度学习实战(19)——使用对抗攻击生成可欺骗神经网络的图像
Keras深度学习实战(20)——DeepDream模型详解
Keras深度学习实战(21)——神经风格迁移详解
Keras深度学习实战(22)——生成对抗网络详解与实现
Keras深度学习实战(23)——DCGAN详解与实现
Keras深度学习实战(24)——从零开始构建单词向量
Keras深度学习实战(25)——使用skip-gram和CBOW模型构建单词向量
Keras深度学习实战(26)——文档向量详解
Keras深度学习实战(27)——循环神经详解与实现
Keras深度学习实战(28)——利用单词向量构建情感分析模型
Keras深度学习实战(29)——长短时记忆网络详解与实现
Keras深度学习实战(30)——使用文本生成模型进行文学创作
Keras深度学习实战(31)——构建电影推荐系统
Keras深度学习实战(32)——基于LSTM预测股价
Keras深度学习实战(33)——基于LSTM的序列预测模型
Keras深度学习实战(34)——构建聊天机器人
Keras深度学习实战(35)——构建机器翻译模型
Keras深度学习实战(36)——基于编码器-解码器的机器翻译模型
Keras深度学习实战(37)——手写文字识别
Keras深度学习实战(38)——图像字幕生成
Keras深度学习实战(39)——音乐音频分类
Keras深度学习实战(40)——音频生成
Keras深度学习实战(41)——语音识别
Keras深度学习实战(42)——强化学习基础
转载:https://blog.csdn.net/LOVEmy134611/article/details/126774917