Keras深度学习实战(43)——深度Q学习算法

Posted 盼小辉丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Keras深度学习实战(43)——深度Q学习算法相关的知识,希望对你有一定的参考价值。

Keras深度学习实战(43)——深度Q学习算法

0. 前言

《强化学习基础》一节中,我们学习了强化学习的基本概念,并且介绍了如何在给定状态下采取随机动作。此外,我们还使用自定义环境,计算下一个状态、动作和奖励。在本节中,我们首先介绍 Q 学习与深度 Q 学习的基本思想,然后利用 OpenAIGym 库模拟 Frozen LakeCartPole 问题,并使用 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) π(as) 下,具有以下关系:

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 ) \\beginsplit Q^*(s_t, a_t)=\\undersetπmaxQ^π(s_t, a_t)\\\\ π^*=\\underseta_targmaxQ^*(s_t, a_t) \\endsplit 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\\underseta_t+1maxQ^*(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 4q-表,其中所有元素值为 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 (一个介于 01 之间的随机数)小于 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]
 [以上是关于Keras深度学习实战(43)——深度Q学习算法的主要内容,如果未能解决你的问题,请参考以下文章

Keras深度学习实战——使用循环神经网络构建情感分析模型

Keras深度学习实战——使用GloVe模型构建单词向量

Keras深度学习实战——使用GloVe模型构建单词向量

Keras深度学习实战(20)——神经风格迁移详解

Keras深度学习实战——使用fastText模型构建单词向量

Keras深度学习实战(20)——DeepDream模型详解