Sarsa算法和Q-learning算法

1、马尔可夫决策过程(MDP)四元组

马尔可夫四元组

s:state 状态
a:action 动作
r:reward 奖励
p:policy 状态转移概率 p ( s t + 1 , r t ∣ s t , a t ) p(s_{t+1},r_t | s_t,a_t) p(st+1,rtst,at),变表示在 t 时刻的状态 s t s_t st 下,采取动作 a t a_t at ,状态转移到 s t + 1 s_{t+1} st+1 并且收获奖励 r t r_t rt
的概率。此处,假设假设事件具有马尔科夫性,该决策过程为一个马尔可夫决策过程 (MDP)。
:马尔可夫决策过程四元组(MDP四元组)为 (s,a,r,p)

另外五元组 则是多一个 折扣因子参数 γ用于表示未来对当前的 reward 的影响0≤γ≤1γ=0表示只关注当前 action 在下一步带来的reward;γ=1表示当前 action 在未来所有时间带来的 reward。

2、Q表格

Sarsa和Q-learning都是基于表格的强化学习算法,在此,先对Q表格做简单介绍。

Q表格是一个维度为 M * N 的表格,其中,M表示某一环境下所有的状态 (observation) 数量;N表示所有可采取的行为 (action) 的数量;其中的每一个值Q代表在某一个状态下采取一个行为的长远收益,此处长远收益区别于rewardreward为每一个动作的奖励,Q代表在某一个状态下采取某一个行为在未来会产生的收益,公式如下:

  Q = r e w a r d 1 + γ ∗ r e w a r d 2 + . . . + γ ∗ r e w a r d n \ Q=reward_1+\gamma *reward_2+...+\gamma * reward_n  Q=reward1+γreward2+...+γrewardn

其中,γ∈(0,1),γ=0表示只看当前一步带来的收益;当γ=1表示关注未来所有带来的收益。

举例说明Q表格的作用,以"悬崖漫步"环境为例

observation/action 0 1 2 3
1 0 0 0 0
2 0 0 0 0
3 0 0 0 0

上述示例中,observation 表示所有的状态,action表示所有的行为,在悬崖环境下,observation就是agent的坐标,每个值代表一个坐标,例如1代表(0,0)点;action有四个0,1,2,3分别代表上、下、左、右四个方向的行动。

有了Q表格,就可以根据其中的Q值选取合适的action,不断用选择的action与环境交互得到经验,更新优化Q值,这就是强化学习的过程,最后达到收敛状态。收敛时Q表格的变化应该趋于0.
这也是Sarsa 和 Q-learning的算法的学习思路,下面对两种算法进行说明。

3、Sarsa算法

强化学习中agent 的需要做的两件事:一是选择action(采用ε-greedy方法,在代码视线中会有介绍);二是学习learning,也就是更新Q表格。

Sarsa根据下一步的Q值更新当前的Q值,下面给出Sarsa的流程。

3.1 Sarsa算法流程

首先,Sarsa更新Q值采用**时序差分**的方式进行更新,其更新公式如下:

  Q ∗ ( s t , a t ) = Q ( s t , a t ) + α [ r t + γ Q ( s t + 1 , a t + 1 ) − Q ( s t , a t ) ] \ Q^*(s_t,a_t) = Q(s_t,a_t) + \alpha[r_t+\gamma Q(s_{t+1},a_{t+1})-Q(s_t,a_t)]  Q(st,at)=Q(st,at)+α[rt+γQ(st+1,at+1)Q(st,at)]

该更新方式为 时序差分更新,即:当前值 +【(目标值-当前值)✖ 学习因子 】

Sarsa 的算法流程则是完全按照上述的思路进行:需要当前的状态 s t s_t st,当前的行为 a t a_t at,当前行为的奖励 r t r_t rt,采取当前行为后环境达到的新的状态 s t + 1 s_{t+1} st+1,下一步的行为 a t + 1 a_{t+1} at+1,这也是Sarsa算法名称的由来。

Sarsa算法和Q-learning算法_第1张图片

3.2 Sarsa实现

下面以"悬崖漫步"环境为例,简单介绍Sarsa算法的实现:

首先创建Agent 类,如上所述,实现Agent的两个方法:选择action,更新Q值

"""
# -*- coding:utf-8 -*-
# @Time       :2022/5/27 11:21
# @AUTHOR     :Lxy
# @SOFTWARE   :RL
# @description:
# @para       :
"""
import random

import numpy as np


class Agent:
    """
    :param:observation为所有状态数量
    :param:act_n为所有的策略数量
    :param:epsilong为 ε-greedy 算法中的概率值
    :param:gama为折扣因子,表示当前action在未来带来的收益的衰减因子
    :param:alfa为学习率
    """

    def __init__(self, obser_n, act_n, epsilong, gama, alfa):
        self.act_n = act_n
        self.Q_table = np.zeros((obser_n, act_n))
        self.epsilong = epsilong
        self.gama = gama
        self.alfa = alfa

    """
    根据当前 Observation选择最优 action,采用 ε-greedy 算法,即:ε 概率探索,否则选择Q值最大的策略
    每个observation 用一个数字表示,例如:索引1表示observation(1,1)
    """

    def actionChoose(self, observation):
        Q_observation = self.Q_table[observation, :]
        if random.uniform(0, 1) > (1 - self.epsilong):
            return np.random.choice(self.act_n)
        else:
            return self.getMaxOfQtable(observation)

    #  根据当前Observation返回Q值最大的action
    def getMaxOfQtable(self, observation):
        Q_observation = self.Q_table[observation, :]
        maxList = np.where(Q_observation == max(Q_observation))[0]
        return np.random.choice(maxList)

    #  learn算法,更新Q表格
    def learn(self, observation, action, reward, next_observation, next_action, is_done):
        if is_done:
            target_value = reward
            this_value = self.Q_table[observation][action]
            self.Q_table[observation][action] += self.alfa * (target_value - this_value)
        else:
            #   先计算目标值
            target_value = reward + self.gama * self.Q_table[next_observation][next_action]
            #   拿当前值
            this_value = self.Q_table[observation][action]
            #   计算时序差分
            diff = target_value - this_value
            #   更新当前Q
            self.Q_table[observation][action] += self.alfa * diff

    def getQtable(self):
        return self.Q_table

然后,train.py 用于训练

"""
# -*- coding:utf-8 -*-
# @Time       :2022/5/27 14:13
# @AUTHOR     :Lxy
# @SOFTWARE   :RL
# @description:
# @para       :
"""
import gym
from Agent import Agent
import matplotlib.pyplot as plt


def main():
    env = gym.make("CliffWalking-v0")
    agent = Agent(
        obser_n=env.observation_space.n,
        act_n=env.action_space.n,
        epsilong=0.1,
        gama=0.9,
        alfa=0.01
    )
    rewardList = []
    for epoch in range(1000):
        observation = env.reset()
        action = agent.actionChoose(observation=observation)
        step = 0
        total_reward = 0
        while True:
            next_observation, reward, is_done, _ = env.step(action)
            next_action = agent.actionChoose(next_observation)
            agent.learn(observation, action, reward, next_observation, next_action, is_done)
            observation = next_observation
            action = next_action
            total_reward += reward
            step += 1
            if is_done:
                break
        print("第" + str(epoch + 1) + "个epoch.......")
        print("总step:" + str(step))
        print("总reward:" + str(total_reward))
        print("-------------------------------------------------")
        rewardList.append(total_reward)
    print(agent.getQtable())
    #   绘训练过程图
    plt.plot(rewardList)
    plt.title("Sarsa")
    plt.show()


if __name__ == "__main__":
    main()

4、Q-learning算法

Q-learning算法与Sarsa基本类似,都采用ε-greedy算法选择行为。区别在于,Q-learning在更新下一步的Q值的时候不关心下一步所采取的行为action,而是使用下一步中最大的Q值来更新当前步的Q值。也就是说,Q-learning不管下一步的行为是什么,始终选择下一步最大的行为的Q值来更新当前步的Q值。
这也是Q-learning的两种策略,行为策略目标策略,其中行为策略采用ε-greedy算法选择下一步的i行为;目标策略则选择下一步最大的Q值来更新当前的Q值。而Sarsa中只存在一种策略。

4.1 Q-learning算法流程

Q-learning的Q值更新方式同样采用时序差分的方式,与Sarsa相同,不同点是目标值不同,直接给出Q-learning的Q更新公式:

  Q ∗ ( s t , a t ) = Q ( s t , a t ) + α [ r t + γ max ⁡ a ′ ( Q ( s t + 1 , a ′ ) ) − Q ( s t , a t ) ] \ Q^*(s_t,a_t) = Q(s_t,a_t) + \alpha[r_t+\gamma \max_{a'} (Q(s_{t+1},a'))-Q(s_t,a_t)]  Q(st,at)=Q(st,at)+α[rt+γamax(Q(st+1,a))Q(st,at)]

以及算法流程:

Sarsa算法和Q-learning算法_第2张图片

4.2 Q-learning实现

Q-learning的实现方式与Sarsa相同,只是修改了Q值更新的方式

首先创建Agent 类,如上所述,实现Agent的两个方法:选择action,更新Q值

"""
# -*- coding:utf-8 -*-
# @Time       :2022/5/31 11:45
# @AUTHOR     :Lxy
# @SOFTWARE   :RL
# @description:
# @para       :
"""

import random
import numpy as np


class Agent:
    """
    :param:observation为所有状态数量
    :param:act_n为所有的策略数量
    :param:epsilong为 ε-greedy 算法中的概率值
    :param:gama为折扣因子,表示当前action在未来带来的收益的衰减因子
    :param:alfa为学习率
    """

    def __init__(self, obser_n, act_n, epsilong, gama, alfa):
        self.act_n = act_n
        self.Q_table = np.zeros((obser_n, act_n))
        self.epsilong = epsilong
        self.gama = gama
        self.alfa = alfa

    """
    根据当前 Observation选择最优 action,采用 ε-greedy 算法,即:ε 概率探索,否则选择Q值最大的策略
    每个observation 用一个数字表示,例如:索引1表示observation(1,1)
    """

    def actionChoose(self, observation):
        Q_observation = self.Q_table[observation, :]
        if random.uniform(0, 1) > (1 - self.epsilong):
            return np.random.choice(self.act_n)
        else:
            return self.getMaxOfQtable(observation)

    #  根据当前Observation返回Q值最大的action
    def getMaxOfQtable(self, observation):
        Q_observation = self.Q_table[observation, :]
        maxList = np.where(Q_observation == max(Q_observation))[0]
        return np.random.choice(maxList)

    #  learn算法,更新Q表格
    def learn(self, observation, action, reward, next_observation, next_action, is_done):
        if is_done:
            target_value = reward
            this_value = self.Q_table[observation][action]
            self.Q_table[observation][action] += self.alfa * (target_value - this_value)
        else:
            #   先计算目标值
            target_value = reward + self.gama * max(self.Q_table[next_observation, :])
            #   拿当前值
            this_value = self.Q_table[observation][action]
            #   计算时序差分
            diff = target_value - this_value
            #   更新当前Q
            self.Q_table[observation][action] += self.alfa * diff

    def getQtable(self):
        return self.Q_table

然后,train.py 用于训练

"""
# -*- coding:utf-8 -*-
# @Time       :2022/5/31 11:46
# @AUTHOR     :Lxy
# @SOFTWARE   :RL
# @description:
# @para       :
"""

import gym
from QlearningAgent import Agent
import matplotlib.pyplot as plt


def main():
    env = gym.make("CliffWalking-v0")
    agent = Agent(
        obser_n=env.observation_space.n,
        act_n=env.action_space.n,
        epsilong=0.1,
        gama=0.9,
        alfa=0.01
    )
    rewardList = []
    for epoch in range(1000):
        observation = env.reset()
        action = agent.actionChoose(observation=observation)
        step = 0
        total_reward = 0
        while True:
            next_observation, reward, is_done, _ = env.step(action)
            next_action = agent.actionChoose(next_observation)
            agent.learn(observation, action, reward, next_observation, next_action, is_done)
            observation = next_observation
            action = next_action
            total_reward += reward
            step += 1
            if is_done:
                break
        print("第" + str(epoch + 1) + "个epoch.......")
        print("总step:" + str(step))
        print("总reward:" + str(total_reward))
        print("-------------------------------------------------")
        rewardList.append(total_reward)
    print(agent.getQtable())
    #   绘训练过程图
    plt.plot(rewardList)
    plt.title("Q-learning")
    plt.show()


if __name__ == "__main__":
    main()

5、on-policy和off-policy

理解了Sarsa和Q-learning的区别就能理解on-policy和off-policy,下面再次进行解释

on-policy 在只存在一种策略,无论是选择 action 还是更新Q值,都采用同一种策略,也就是说,on-policy更新Q值采用的 action 和下一步选择的 action 一定是相同的;也就是 Sarsa 算法。
off-policy 存在两种策略,行为策略目标策略,行为策略用于与环境交互,不断探索环境,将环境的反馈回馈给目标策略,目标策略更新Q值。也就是说,off-policy 更新Q和选择 action 不是同一种策略,也就是Q-learning算法。选择下一步实际的 action 时采用是ε-greedy 算法,但是在更新Q值时采用最大的 action。

6、代码

以上所有可执行代码均存放于我的gitee,地址:强化学习

你可能感兴趣的:(强化学习,算法,机器学习,人工智能)