第三章、基于表格方法求RL(1)-Sarsa

第三章、基于表格方法求RL(1)-Sarsa

主要内容为题主在学习机器学习时记录的内容

一、MDP与四元组

1.1 四元组

强化学习MDP四元组<S,A,P,R>分别表示 state-状态action-动作reward-奖励probability-状态转移概率

1.2 MDP介绍

1.2.1 MDP简介

即为马尔可夫决策过程(Markov Decision Process,简称为MDP)。可以参考这篇文章进行学习:MDP
在创造了四元组后的MDP中,它的状态转移概率 P 由状态 S 与输入的行动 A 共同决定。而 R也是MDP的一个重要元素,服从概率分布:
在这里插入图片描述

1.2.2 Model-based

在P函数和R函数已知的情况下,即你知道每一步的后果和下一步的状态,这样的模式叫做Model-based,这种情况并不适合使用强化学习来解决,更适合动态规划来研究。
在这里插入图片描述
如图的熊追人问题,已经有了一张比较清晰的决策树,你知道每一步的后果,那你就会选择收益最大的一步,这比较适合动态规划。

1.2.3 Model-free

而强化学习比较适合于无模型状态,你并不知道每一步的后果和下一步该做什么,你只能通过不断地试错并积累经验,从而把自己训练为对每一步都知道如何做的大神。

1.3 Q表格

1.3.1 Q表格概述

那强化学习如何记录每一步的后果,即记住每一步的经验呢?
最简单的方法是通过Q表格的方式来记录。Q即 Q(s,a),行表示每一个动作a,列表示每一个状态s,合起来就是某状态s下,做某动作a,得到的下一个状态st+1.
在这里插入图片描述

1.3.2 未来总收益

Q表格可以指导每一个Step的动作选项,它的目标导向为未来的总收益最大。对于未来总收益G的计算,常规的想法是 G=R1+R2+R3+…+Rt。
但是当前动作的价值,单纯地用未来所有的收益相加并不合理。
比如股票预测,单纯考虑未来收益之和并不合理,短期的变化更为重要。
所以就引入了衰减因子的概念。
在这里插入图片描述
通过引入衰减因子,可以让未来的较长时间后的 R 的影响作用变小,从而使得结果更注重近期的 R。
γ 等于 1 相当于每一步都考虑,γ 设为0则相当于只看下一步。

二、TD

2.1 强化概念

强化就是让智能体通过多次学习,不断地重复训练,使得下一个状态的价值可以不断地强化影响上一个状态的价值。
类似于条件反射,在训练狗狗握手的时候,你可以通过给狗粮的方式进行奖励,如果握手成功就给狗粮,握手成功的次数越多,给狗粮越多,则狗的脑子中握手就有狗粮吃的概念越被强化,最终学会握手。

2.2 TD-Temporal Difference

2.2.1 概念

这里可以详细学习该博主的文章(向大牛致敬!)。
TD是指 Temporal Difference ,时序差分。相比于DP(environment model信息非常全)MC(蒙特卡洛,按episode学习),TD的方式是step-by-step
MC算法需要等到一个episode 结束后才能更新value,TD和DP可以单步更新,但区别在于TD不需要知道确切的环境模型(状态转移概率等),可以根据下一步的估计来更新当前估计value。
也就是说太TD综合了DP单步和MC学习的优点。

2.2.2 数学公式

α 类似学习率,γ 是衰减因子,使用目标值减去当前值,在乘以学习率后加上当前值,用一种软更新的方式使得 Q 不断逼近于目标值。(有一说一没懂)
在这里插入图片描述

三、Sarsa

3.1 Sarsa引入

TD中的当前状态和动作,决定下一个状态和动作与奖励的方式,就是Sarsa算法。
Sarsa 就是(St,At,Rt+1,St+1,At+1)。
在这里插入图片描述

3.2 Sarsa介绍

在这里插入图片描述
核心就是拿下一步的Q值来更新这一步的Q值,不断强化每一个Q。

3.2.1 Sarsa伪代码

在这里插入图片描述
reset 是重置函数。
sample 是动作选择函数。
learn 是更新Q表格函数。
执行learn函数之前,需要先拿到next_obs, 来更新next_action。这是与Q-learning函数不同的地方。

3.2.2 Sarsa逻辑步骤

在这里插入图片描述
流程图:
在这里插入图片描述

3.3 ε-greedy

3.3.1 ε-greedy 策略

sample 函数使用了 ε-greedy 的方法。ε-greedy 是一个贪心地探索与利用的函数。
其表示在智能体做决策时,有一很小的正数ϵ ( < 1 )的概率随机选择未知的一个动作,剩下1 − ϵ 的概率选择已有动过中动作价值最大的动作。

3.3.2 ε-greedy 伪代码

在这里插入图片描述
predict 函数 是在已有的经验中挑选实现下一步的动作,即在已有的Q表格中查询。
samole 函数 是采样,保证除了能拿到最优的动作,其他的动作也有概率被采样到。

四、Sarsa 代码样例

问题描述:使小乌龟从左下角自学习的走到右下角,注意不要掉入悬崖(黑色),掉入悬崖则重新开始。
在这里插入图片描述

import gym
import numpy as np
import time

# agent代码
class SarsaAgent(object):
    def __init__(self, obs_n, act_n, learning_rate=0.01, gamma=0.9, e_greed=0.1):
        self.act_n = act_n      # 动作维度,有几个动作可选
        self.lr = learning_rate # 学习率
        self.gamma = gamma      # reward的衰减率
        self.epsilon = e_greed  # 按一定概率随机选动作
        self.Q = np.zeros((obs_n, act_n))

    # 根据输入观察值,采样输出的动作值,带探索
    def sample(self, obs):
        if np.random.uniform(0, 1) < (1.0 - self.epsilon): #根据table的Q值选动作
            action = self.predict(obs)
        else:
            action = np.random.choice(self.act_n) #有一定概率随机探索选取一个动作
        return action

    # 根据输入观察值,预测输出的动作值
    def predict(self, obs):
        Q_list = self.Q[obs, :]
        maxQ = np.max(Q_list)
        action_list = np.where(Q_list == maxQ)[0]  # maxQ可能对应多个action
        action = np.random.choice(action_list)
        return action

    # 学习方法,也就是更新Q-table的方法
    def learn(self, obs, action, reward, next_obs, next_action, done):
        """ on-policy
            obs: 交互前的obs, s_t
            action: 本次交互选择的action, a_t
            reward: 本次动作获得的奖励r
            next_obs: 本次交互后的obs, s_t+1
            next_action: 根据当前Q表格, 针对next_obs会选择的动作, a_t+1
            done: episode是否结束
        """
        predict_Q = self.Q[obs, action]
        if done:
            target_Q = reward # 没有下一个状态了
        else:
            target_Q = reward + self.gamma * self.Q[next_obs, next_action] # Sarsa
        self.Q[obs, action] += self.lr * (target_Q - predict_Q) # 修正q

    # 保存Q表格数据到文件
    def save(self):
        npy_file = './q_table.npy'
        np.save(npy_file, self.Q)
        print(npy_file + ' saved.')
    
    # 从文件中读取Q值到Q表格中
    def restore(self, npy_file='./q_table.npy'):
        self.Q = np.load(npy_file)
        print(npy_file + ' loaded.')

def run_episode(env, agent, render=False):
    total_steps = 0 # 记录每个episode走了多少step
    total_reward = 0

    obs = env.reset() # 重置环境, 重新开一局(即开始新的一个episode)
    action = agent.sample(obs) # 根据算法选择一个动作

    while True:
        next_obs, reward, done, _ = env.step(action) # 与环境进行一个交互
        next_action = agent.sample(next_obs) # 根据算法选择一个动作
        # 训练 Sarsa 算法
        agent.learn(obs, action, reward, next_obs, next_action, done)

        action = next_action
        obs = next_obs  # 存储上一个观察值
        total_reward += reward
        total_steps += 1 # 计算step数
        if render:
            env.render() #渲染新的一帧图形
        if done:
            break
    return total_reward, total_steps


def test_episode(env, agent):
    total_reward = 0
    obs = env.reset()
    while True:
        action = agent.predict(obs) # greedy
        next_obs, reward, done, _ = env.step(action)
        total_reward += reward
        obs = next_obs
        # time.sleep(0.5)
        # env.render()
        if done:
            break
    return total_reward

# 使用gym创建悬崖环境
env = gym.make("CliffWalking-v0")  # 0 up, 1 right, 2 down, 3 left

# 创建一个agent实例,输入超参数
agent = SarsaAgent(
        obs_n=env.observation_space.n,
        act_n=env.action_space.n,
        learning_rate=0.1,
        gamma=0.9,
        e_greed=0.1)


# 训练500个episode,打印每个episode的分数
for episode in range(500):
    ep_reward, ep_steps = run_episode(env, agent, False)
    print('Episode %s: steps = %s , reward = %.1f' % (episode, ep_steps, ep_reward))

# 全部训练结束,查看算法效果
test_reward = test_episode(env, agent)
print('test reward = %.1f' % (test_reward))

运行结果:
在这里插入图片描述
最后的路线为:
在这里插入图片描述
之所以路线会这样,是因为Sarsa的最终的结果为,即使下一步会有随机动作,但仍然在安全范围内。所以会远离悬崖,即使这样的收益不是最大。
这与Q-learning的结果有很大的区别。
建议直接在百度的 AI Studio 上运行,速度快,安装包还特别方便。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值