强化学习总结(有具体代码实现)

news2024/9/28 17:36:15

文章目录

  • 第一部分 强化学习基础
    • 第1章 强化学习概述
      • 1.1 强化学习概念
      • 1.2 强化学习的环境
      • 1.3 强化学习的目标
      • 1.4 强化学习的数据
    • 第2章 多臂老虎机问题(MAB问题)
      • 2.1 问题描述
        • 2.1.1 问题定义
        • 2.1.2 形式化描述
        • 2.1.3 累积懊悔
        • 2.1.4 估计期望奖励
      • 2.2 解决方法
        • 2.2.1 ϵ-贪婪算法
        • 2.2.2 上置信界算法
        • 2.2.3 汤普森采样算法
        • 2.2.4 小结
    • 第3章 马尔可夫决策过程
      • 3.1 马尔可夫过程
      • 3.2 马尔可夫奖励过程
        • 3.2.1 定义
        • 3.2.2 回报
        • 3.2.3 价值函数
      • 3.3 马尔可夫决策过程
      • 3.4 蒙特卡洛方法
      • 3.5 占用度量
      • 3.6 最优策略
    • 第4章 动态规划算法
    • 第5章 时序差分算法
    • 第6章 Dyna-Q 算法
  • 第二部分 强化学习进阶
    • 第7章 DQN 算法
    • 第8章 DQN 改进算法
    • 第9章 策略梯度算法
    • 第10章 Actor-Critic 算法
    • 第11章 TRPO 算法
    • 第12章 PPO 算法
    • 第13章 DDPG 算法
    • 第14章 SAC 算法
  • 第三部分 强化学习前沿
    • 第15章 模仿学习
    • 第16章 模型预测控制
    • 第17章 基于模型的策略优化
    • 第18章 离线强化学习
    • 第19章 目标导向的强化学习
    • 第20章 多智能体强化学习入门
    • 第21章 多智能体强化学习进阶

第一部分 强化学习基础

第1章 强化学习概述

1.1 强化学习概念

  1. 定义:强化学习是机器通过与环境交互来实现目标的一种计算方法。
    机器与环境的一轮交互:机器在环境的一个状态下做一个动作决策,动作执行后,环境发生改变并把相应的奖励反馈和下一轮状态传回机器。
  2. 交互
    在这里插入图片描述
    • 感知:智能体在某种程度上感知环境的状态
    • 决策:智能体根据当前状态计算出到达目标需要采取的动作的过程;
      策略是智能体最终体现的智能形式,是不同智能体之间的核心区别
    • 奖励:环境根据状态和智能体采取的动作,产生一个标量信号作为奖励反馈;
      最大化累计奖励期望是智能体提升策略的目标,也是衡量智能体策略好坏的关键指标

1.2 强化学习的环境

  环境的下一刻状态的概率分布由当前状态和智能体的动作共同决定,公式如下:

环境的下一刻状态 ∼ P ( ⋅ ∣ 当前状态,智能体的动作 ) 环境的下一刻状态 \sim P(\cdot | 当前状态,智能体的动作) 环境的下一刻状态P(当前状态,智能体的动作)

1.3 强化学习的目标

  • 整体回报:整个交互过程的每一轮获得的奖励信号的累加,类似一盘游戏最后的得分。
  • 价值:回报的期望,也是智能体学习的优化目标。
    计算方式:需要对交互过程中每一轮智能体采取动作的概率分布和环境相应的状态转移的概率分布做积分运算。

1.4 强化学习的数据

  在强化学习中,数据是智能体与环境交互的过程中得到的。如果智能体不采取某个决策动作,那么该动作对于的数据就无法被观测到,所以当前智能体的训练数据来自之前智能体的决策结果。因此,策略不同,得到的数据分布就不同。

  强化学习中有一个关于数据分布的概念,叫作占用度量。归一化的占用度量用于衡量在交互过程中,采样到一个具体的状态动作对的概率分布。

  占用度量的一个重要性质:占用度量相同当且仅当策略相同。因此,寻找最优策略对应寻找最优占用度量。

第2章 多臂老虎机问题(MAB问题)

2.1 问题描述

2.1.1 问题定义

  有一个用于 K 根拉杆的老虎机,每一根拉杆都对应一个关于奖励的概率分布 R 。每拉动一个拉杆,就可以从该拉杆的奖励概率分布中获得一个奖励 r 。在各拉杆的奖励概率分布未知的情况下,从头开始尝试,目标是在操作 T 次拉杆后获得尽可能高的累积奖励。

  由于奖励的概率分布是未知的,因此我们需要在“探索拉杆的获奖概率”和“根据经验选择获奖多的拉杆”中进行权衡。

【通俗易懂:有 K 个机器,你不知道每个机器的奖励概率分布,你只有 T 次机会选择机会,探索机器的奖励概率分布也算在 T 次内,然后尽可能获得最多的奖励。】

【示例:有 1 个 10 臂老虎机,你有 20 次选择机会,你可以花 10 次机会探索前 5 臂,根据获得的奖励,选择奖励期望最大的一个,剩下 10 次都选择最大的那 1 臂。(有可能奖励期望最大在没有探索的 5 臂中,也有可能在前 5 臂中,但是不是你选择的那个)】

2.1.2 形式化描述

  多臂老虎机问题可以表示为一个元组 < A ,    R > <A,\;R> <A,R>,其中:

  • A 为动作集合,其中一个动作表示拉动一根拉杆,若多臂老虎机有 K 个拉杆,则动作空间就是集合 { a 1 , a 2 , . . . , a K } \{a_1,a_2,...,a_K\} {a1,a2,...,aK},用 a t ∈ A a_t \in A atA 表示任意一个动作;
  • R 为概率分布,拉动每一根拉杆的动作 a 都对应一个奖励概率分布 R ( r ∣ a ) R(r|a) R(ra),拉动不同拉杆的奖励分布通常是不同。

  假设每个时间步只能拉动 1 根拉杆,多臂老虎机的目标为最大化一段时间步 T 内累积的奖励: m a x ∑ t = 1 T r t ,    r t ∼ R ( ⋅ ∣ a t ) max\sum^T_{t=1}r_t,\;r_t\sim R(\cdot|a_t) maxt=1Trt,rtR(at)。其中 a t a_t at 表示在第 t 时间步拉动某一拉杆的动作, r t r_t rt 表示动作 a t a_t at 获得的奖励。

2.1.3 累积懊悔

  对于每一个动作 a ,我们定义其期望奖励为 Q ( a ) = E r ∼ R ( ⋅ ∣ a ) [ r ] Q(a)=E_{r\sim R(\cdot | a)}[r] Q(a)=ErR(a)[r] 。于是,至少存在一根拉杆,它的期望奖励不小于任意一根拉杆,将该最优期望奖励表示为 Q ∗ = max ⁡ a ∈ A Q ( a ) Q^*=\max_{a\in A}Q(a) Q=maxaAQ(a)

  • 懊悔:当前动作 a 与最优拉杆期望奖励的差距,即 R ( a ) = Q ∗ − Q ( a ) R(a)=Q^*-Q(a) R(a)=QQ(a)
  • 累积懊悔:操作 T 次拉杆后累积的懊悔总量,对于一次完整的 T 步决策 { a 1 , a 2 , . . . , a T } \{a_1,a_2,...,a_T\} {a1,a2,...,aT} ,累积懊悔为: σ R = ∑ t = 1 T R ( a t ) \sigma_R=\sum^T_{t=1}R(a_t) σR=t=1TR(at)

  所以求解 MAB 问题等价于最小化累积懊悔

2.1.4 估计期望奖励

  为了知道拉动哪一根拉杆可以获得更高的奖励,所以我们需要估计这根拉杆的期望奖励。

算法流程:

对于 ∀ a ∈ A \forall a\in A aA ,初始化计算器 N ( a ) = 0 N(a)=0 N(a)=0 和 期望奖励估值 Q ^ ( a ) = 0 \hat{Q}(a)=0 Q^(a)=0
for t = 1 → T t=1 \rightarrow T t=1T do
  选取某根拉杆,该动作记为 a t a_t at
  得到奖励 r t r_t rt
  更新计数器: N ( a t ) + = 1 N(a_t)+=1 N(at)+=1
  更新期望奖励估值: Q ^ ( a t ) + = 1 N ( a t ) [ r t − Q ^ ( a t ) ] \hat{Q}(a_t)+=\frac{1}{N(a_t)}[r_t-\hat{Q}(a_t)] Q^(at)+=N(at)1[rtQ^(at)]

示例:

  编写一个拉杆为 10 的多臂老虎机。其中每个拉杆的奖励服从伯努利分布,即每次有 p 的概率获得奖励 1 ,有 1-p 的概率获得奖励 0 。【0 表示没有获奖,1 表示获奖。】

在 MAB 目录下新建 BernoulliBandit.py 文件
在这里插入图片描述
代码如下:

import numpy as np
import matplotlib.pyplot as plt


class BernoulliBandit:
    """伯努利多臂老虎机,输入 K 表示拉杆个数"""

    def __init__(self, K):
        self.probs = np.random.uniform(size=K)  # 随机生成 K 个 0-1 的数,表示每个拉杆的获奖概率
        self.best_idx = np.argmax(self.probs)  # 获奖概率最大的拉杆
        self.best_prob = self.probs[self.best_idx]  # 最大的获奖概率
        self.K=K

    def step(self, k):
        if np.random.rand() < self.probs[k]:
            return 1
        else:
            return 0


np.random.seed(1)
K = 10
bandit = BernoulliBandit(K)
print("随机生成了一个 %d 臂的伯努利多臂老虎机" % K)
print("获奖概率最大的拉杆为 %d 号,其获奖概率为 %.4f" % (bandit.best_idx, bandit.best_prob))

运行结果如下:

D:\RL\MAB\.venv\Scripts\python.exe D:\RL\MAB\BernoulliBandit.py 
随机生成了一个10臂的伯努利多臂老虎机
获奖概率最大的拉杆为1 号,其获奖概率为0.7203

进程已结束,退出代码为 0

  接下来编写 Solver 基础类来解决 MAB 问题。具体的解决策略由每个继承 Solver 的类来实现。

  新建 Solver.py 文件,文件代码如下:

import numpy as np


class Solver:
    """多臂老虎机解决方案抽象类"""

    def __init__(self, bandit):
        self.bandit = bandit
        self.counts = np.zeros(self.bandit.K) # 每根拉杆的尝试次数
        self.regret = 0 # 当前步的累积懊悔
        self.actions = []   # 记录每一步的动作
        self.regrets = []   # 记录每一步的累积懊悔

    def update_regret(self, k):
        # 记录累积懊悔并保存,k为本次动作选择的拉杆的编号
        self.regret += self.bandit.best_prob - self.bandit.probs[k]
        self.regrets.append(self.regret)

    def run_one_step(self):
        # 返回当前动作选择的拉杆,由具体的策略实现
        raise NotImplementedError

    def run(self, num_steps):
        # 运行一定次数,num_steps为总运行次数
        for _ in range(num_steps):
            k = self.run_one_step()
            self.counts[k] += 1
            self.actions.append(k)
            self.update_regret(k)

可能遇到的问题与解决方案

  1. 没有配置 numpy 的模块
    在这里插入图片描述
    解决方案:
    点击设置
    在这里插入图片描述
    在项目:xxxx 的 Python 解释器中,点击 + 号
    在这里插入图片描述
    输入 numpy ,选择第一个,点击安装软件包
    在这里插入图片描述
    安装成功后关闭该界面
    在这里插入图片描述
    此时发现项目软件包中多了 numpy,点击确定即可。
    在这里插入图片描述
  2. 没有配置 matplotlib 的模块
    解决方案:
    同上,只是搜索 matplotlib 即可
    在这里插入图片描述

2.2 解决方法

2.2.1 ϵ-贪婪算法

  完全贪婪算法就是在每一刻都采取期望奖励估值最大的动作,这就是纯粹的利用,没有探索。而 ε-贪婪算法则是在其基础上添加了噪声,每次以 1-ε 的概率选择以往经验中期望奖励估值最大的那根拉杆【利用】,以 ε 的概率随机选择一根拉杆【探索】,公式如下:

a t = { a r g    max ⁡ a ∈ A Q ^ ,采样概率: 1 − ϵ 从 A 中随机选择,采样概率: ϵ a_t= \left\{ \begin{array}{ll} arg\; \max\limits_{a\in A} \hat{Q},采样概率:1-\epsilon \\ 从A中随机选择,采样概率:\epsilon \end{array} \right. at={argaAmaxQ^,采样概率:1ϵA中随机选择,采样概率:ϵ

  随着探索次数不断的增多,对各个动作的奖励估计越来越准确,所以没必要继续花费大力气进行探索。所以我们可以让 ε 随着时间衰减,但是不会到 0 。因为基于有限步观测的完全贪婪算法仍然是一个局部信息的贪婪算法,永远离最优解有一个固定的差距。

项目结构:

在这里插入图片描述

新建 EpsilonGreedy.py 文件,文件代码如下:

import numpy as np

from Solver import Solver


class EpsilonGreedy(Solver):
    def __init__(self,bandit,epsilon=0.01,init_prob=1.0):
        super(EpsilonGreedy,self).__init__(bandit)
        self.epsilon = epsilon
        self.estimates=np.array([init_prob]*self.bandit.K)

    def run_one_step(self):
        if np.random.random()<self.epsilon:
            k=np.random.randint(0,self.bandit.K)
        else:
            k=np.argmax(self.estimates)
        r=self.bandit.step(k)
        self.estimates[k]+=1./(self.counts[k]+1)*(r-self.estimates[k])
        return k

在新建 Main.py 文件,文件代码如下:

import numpy as np
from matplotlib import pyplot as plt

from BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedy


def plot_results(solvers, solver_names):
    """输出解决方法的累积懊悔变化图"""
    for idx, solver in enumerate(solvers):
        time_list = range(len(solver.regrets))
        plt.plot(time_list, solver.regrets, label=solver_names[idx])
    plt.xlabel('Time Step')
    plt.ylabel('Cumulative regrets')
    plt.title('%d-arm bandit' % solvers[0].bandit.K)
    plt.legend()
    plt.show()


np.random.seed(1)
epsilon_greedy_solver = EpsilonGreedy(bandit, epsilon=0.01)
epsilon_greedy_solver.run(5000)
print('epsilon-贪婪算法的累积懊悔为:', epsilon_greedy_solver.regret)
plot_results([epsilon_greedy_solver], ["EpsilonGreedy"])

运行 Main.py 文件,结果如下:

在这里插入图片描述

随机生成了一个 10 臂的伯努利多臂老虎机
获奖概率最大的拉杆为 1 号,其获奖概率为 0.7203
epsilon-贪婪算法的累积懊悔为: 25.526630933945313

  接下来尝试不同 ε 取值的结果:

修改 Main.py 代码如下:

import numpy as np
from matplotlib import pyplot as plt

from BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedy


def plot_results(solvers, solver_names):
    """输出解决方法的累积懊悔变化图"""
    for idx, solver in enumerate(solvers):
        time_list = range(len(solver.regrets))
        plt.plot(time_list, solver.regrets, label=solver_names[idx])
    plt.xlabel('Time Step')
    plt.ylabel('Cumulative regrets')
    plt.title('%d-arm bandit' % solvers[0].bandit.K)
    plt.legend()
    plt.show()


# np.random.seed(1)
# epsilon_greedy_solver = EpsilonGreedy(bandit, epsilon=0.01)
# epsilon_greedy_solver.run(5000)
# print('epsilon-贪婪算法的累积懊悔为:', epsilon_greedy_solver.regret)
# plot_results([epsilon_greedy_solver], ["EpsilonGreedy"])

np.random.seed(0)
epsilons = [1e-4, 0.01, 0.1, 0.25, 0.5]
epsilon_greedy_solver_list = [EpsilonGreedy(bandit, epsilon=e) for e in epsilons]
epsilon_greedy_solver_names = ['epsilon={}'.format(e) for e in epsilons]
for epsilon_greedy_solver in epsilon_greedy_solver_list:
    epsilon_greedy_solver.run(5000)

plot_results(epsilon_greedy_solver_list, epsilon_greedy_solver_names)

运行 Main.py 文件,结果如下:

在这里插入图片描述

随机种子为 0 的结果很完美,但是选择随机种子为 1 的话,这是实验结果:

在这里插入图片描述

但是将时间步扩大为 50000,实验结果又变回来了

在这里插入图片描述

  接下来尝试 ε 随着时间反比例衰减,公式为: ϵ t = 1 t \epsilon_t=\frac1t ϵt=t1

修改 EpsilonGreedy.py 文件,文件代码如下:

import numpy as np

from Solver import Solver


class EpsilonGreedy(Solver):
    def __init__(self, bandit, epsilon=0.01, init_prob=1.0):
        super(EpsilonGreedy, self).__init__(bandit)
        self.epsilon = epsilon
        self.estimates = np.array([init_prob] * self.bandit.K)

    def run_one_step(self):
        if np.random.random() < self.epsilon:
            k = np.random.randint(0, self.bandit.K)
        else:
            k = np.argmax(self.estimates)
        r = self.bandit.step(k)
        self.estimates[k] += 1. / (self.counts[k] + 1) * (r - self.estimates[k])
        return k


class DecayingEpsilonGreedy(Solver):
    def __init__(self, bandit, init_prob=1.0):
        super(DecayingEpsilonGreedy, self).__init__(bandit)
        self.estimates = np.array([init_prob] * self.bandit.K)
        self.total_count = 0

    def run_one_step(self):
        self.total_count += 1
        if np.random.random() < 1 / self.total_count:
            k = np.random.randint(0, self.bandit.K)
        else:
            k = np.argmax(self.estimates)
        r = self.bandit.step(k)
        self.estimates[k] = 1. / (self.counts[k] + 1) * (r - self.estimates[k])

        return k

修改 Main.py 文件,文件代码如下:

import numpy as np
from matplotlib import pyplot as plt

from BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedy, DecayingEpsilonGreedy


def plot_results(solvers, solver_names):
    """输出解决方法的累积懊悔变化图"""
    for idx, solver in enumerate(solvers):
        time_list = range(len(solver.regrets))
        plt.plot(time_list, solver.regrets, label=solver_names[idx])
    plt.xlabel('Time Step')
    plt.ylabel('Cumulative regrets')
    plt.title('%d-arm bandit' % solvers[0].bandit.K)
    plt.legend()
    plt.show()


# np.random.seed(1)
# epsilon_greedy_solver = EpsilonGreedy(bandit, epsilon=0.01)
# epsilon_greedy_solver.run(5000)
# print('epsilon-贪婪算法的累积懊悔为:', epsilon_greedy_solver.regret)
# plot_results([epsilon_greedy_solver], ["EpsilonGreedy"])


# np.random.seed(1)
# epsilons = [1e-4, 0.01, 0.1, 0.25, 0.5]
# epsilon_greedy_solver_list = [EpsilonGreedy(bandit, epsilon=e) for e in epsilons]
# epsilon_greedy_solver_names = ['epsilon={}'.format(e) for e in epsilons]
# for epsilon_greedy_solver in epsilon_greedy_solver_list:
#     epsilon_greedy_solver.run(50000)
# plot_results(epsilon_greedy_solver_list, epsilon_greedy_solver_names)


np.random.seed(1)
decaying_epsilon_greedy_solver = DecayingEpsilonGreedy(bandit)
decaying_epsilon_greedy_solver.run(5000)
print('epsilon 反比衰减的贪婪算法的累积懊悔为:', decaying_epsilon_greedy_solver.regret)
plot_results([decaying_epsilon_greedy_solver], ["DecayingEpsilonGreedy"])

运行 Main.py 文件,结果如下:

在这里插入图片描述

D:\RL\MAB\.venv\Scripts\python.exe D:\RL\MAB\Main.py 
随机生成了一个 10 臂的伯努利多臂老虎机
获奖概率最大的拉杆为 1 号,其获奖概率为 0.7203
epsilon 反比衰减的贪婪算法的累积懊悔为: 10.114334931260183

进程已结束,退出代码为 0

这是扩大时间步至 50000 的结果:

在这里插入图片描述

  从实验结果可以发现,反比例衰减的 ε-贪婪算法可以使得累积懊悔与时间步的关系变为次线性,这明显优于固定 ε 值的 ε-贪婪算法。

2.2.2 上置信界算法

  对于多臂老虎机来说,一根拉杆的探索次数较少,它的不确定性就很高。不确定越高,它具有的探索价值就越大。为此,引入不确定性度量 U(a) ,它随着一个动作被尝试次数的增加而减少。【说白了就是新鲜感】

  上置信界(UCB)算法是一种经典的基于不确定性的策略算法,其思想是基于霍夫丁不等式。在霍夫丁不等式中,令 X 1 , X 2 , . . . , X n X_1,X_2,...,X_n X1,X2,...,Xn 为 n 个独立同分布的随机变量,取值范围为 [0,1] ,其经验期望为 x ˉ = 1 n ∑ j = 1 n X j \bar{x}=\frac1n\sum ^n_{j=1}X_j xˉ=n1j=1nXj ,则有 P ( E [ X ] ≥ x ˉ + u ) ≤ e − 2 n u 2 P(E[X]\ge\bar{x}+u)\le e^{-2nu^2} P(E[X]xˉ+u)e2nu2

  将霍夫丁不等式运用到多臂老虎机问题中。 Q ^ \hat{Q} Q^ 代入 x ˉ \bar{x} xˉ,不等式中 u = U ^ ( a t ) u=\hat{U}(a_t) u=U^(at) 代表不确定性度量。给定一个概率 p = e − 2 N ( a t ) U ( a t ) 2 p=e^{-2N(a_t)U(a_t)^2} p=e2N(at)U(at)2 ,根据上述不等式, Q ( a t ) < Q ^ ( a t ) + U ^ ( a t ) Q(a_t)<\hat{Q}(a_t)+\hat{U}(a_t) Q(at)<Q^(at)+U^(at) 至少以概率 1 − p 1 - p 1p 成立,当 p 很小时, Q ( a t ) < Q ^ ( a t ) + U ^ ( a t ) Q(a_t)<\hat{Q}(a_t)+\hat{U}(a_t) Q(at)<Q^(at)+U^(at) 就以很大概率成立,所以 Q ^ ( a t ) + U ^ ( a t ) \hat{Q}(a_t)+\hat{U}(a_t) Q^(at)+U^(at) 就是期望奖励上界。

  根据 p = e − 2 N ( a t ) U ( a t ) 2 p=e^{-2N(a_t)U(a_t)^2} p=e2N(at)U(at)2 得知 U ^ ( a t ) = − log ⁡ p 2 N ( a t ) \hat{U}(a_t)=\sqrt{\frac{-\log p}{2N(a_t)}} U^(at)=2N(at)logp ,其中 N ( a t ) N(a_t) N(at) 是该拉杆的已经拉动的次数。确定概率 p 就可以计算 U ^ ( a t ) \hat{U}(a_t) U^(at)

  在实际编程中,令 p = 1 t p=\frac1t p=t1 ;令 U ^ ( a t ) = − log ⁡ p 2 ( N ( a t ) + 1 ) \hat{U}(a_t)=\sqrt{\frac{-\log p}{2(N(a_t)+1)}} U^(at)=2(N(at)+1)logp ,以免出现分母为 0 的情况;令 a t = a r g    m a x a ∈ A [ Q ^ ( a ) + c ⋅ U ^ ( a ) ] a_t=arg\;max_{a\in A}[\hat{Q}(a)+c\cdot\hat{U}(a)] at=argmaxaA[Q^(a)+cU^(a)] ,用系数 c 来控制不确定性比重。

新建 UCB.py 文件,文件代码如下:

import numpy as np

from Solver import Solver


class UCB(Solver):
    def __init__(self, bandit, c, init_prob=1.0):
        super(UCB, self).__init__(bandit)
        self.total_count = 0
        self.estimates = np.array([init_prob] * self.bandit.K)
        self.c = c

    def run_one_step(self):
        self.total_count += 1
        ucb = self.estimates + self.c * np.sqrt(np.log(self.total_count) / (2 * (self.counts + 1)))  # 计算上置信界
        k = np.argmax(ucb)
        r = self.bandit.step(k)
        self.estimates[k] += 1. / (self.counts[k] + 1) * (r - self.estimates[k])
        return k

修改 Main.py 文件,文件代码如下:

import numpy as np
from matplotlib import pyplot as plt

from BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedy, DecayingEpsilonGreedy
from UCB import UCB


def plot_results(solvers, solver_names):
    """输出解决方法的累积懊悔变化图"""
    for idx, solver in enumerate(solvers):
        time_list = range(len(solver.regrets))
        plt.plot(time_list, solver.regrets, label=solver_names[idx])
    plt.xlabel('Time Step')
    plt.ylabel('Cumulative regrets')
    plt.title('%d-arm bandit' % solvers[0].bandit.K)
    plt.legend()
    plt.show()


def apply_epsilon_greedy_1():
    np.random.seed(1)
    epsilon_greedy_solver = EpsilonGreedy(bandit, epsilon=0.01)
    epsilon_greedy_solver.run(5000)
    print('epsilon-贪婪算法的累积懊悔为:', epsilon_greedy_solver.regret)
    plot_results([epsilon_greedy_solver], ["EpsilonGreedy"])


def apply_epsilon_greedy_2():
    np.random.seed(1)
    epsilons = [1e-4, 0.01, 0.1, 0.25, 0.5]
    epsilon_greedy_solver_list = [EpsilonGreedy(bandit, epsilon=e) for e in epsilons]
    epsilon_greedy_solver_names = ['epsilon={}'.format(e) for e in epsilons]
    for epsilon_greedy_solver in epsilon_greedy_solver_list:
        epsilon_greedy_solver.run(50000)
    plot_results(epsilon_greedy_solver_list, epsilon_greedy_solver_names)


def apply_decaying_epsilon_greedy():
    np.random.seed(1)
    decaying_epsilon_greedy_solver = DecayingEpsilonGreedy(bandit)
    decaying_epsilon_greedy_solver.run(50000)
    print('epsilon 反比衰减的贪婪算法的累积懊悔为:', decaying_epsilon_greedy_solver.regret)
    plot_results([decaying_epsilon_greedy_solver], ["DecayingEpsilonGreedy"])


def apply_UCB():
    np.random.seed(1)
    c = 1  # 不确定性比重
    UCB_solver = UCB(bandit, c)
    UCB_solver.run(5000)
    print('上置信界算法累积懊悔为:', UCB_solver.regret)
    plot_results([UCB_solver], ["UCB"])

apply_UCB()

运行 Main.py 文件,结果如下:

在这里插入图片描述

D:\RL\MAB\.venv\Scripts\python.exe D:\RL\MAB\Main.py 
随机生成了一个 10 臂的伯努利多臂老虎机
获奖概率最大的拉杆为 1 号,其获奖概率为 0.7203
上置信界算法累积懊悔为: 70.45281214197854

进程已结束,退出代码为 0
2.2.3 汤普森采样算法

  MAB问题还有一种经典算法——汤普森采样,先假设每个拉杆的奖励服从特定的概率分布,然后根据每个拉杆的期望奖励来进行选择。但是计算所有拉杆的期望奖励的代价比较高,所以该算法使用采样的方式,即根据当前每个动作 a 的奖励概率分布进行一轮采样,得到一组拉杆的奖励样本,再选择样本中奖励最大的动作。【汤普森采样是一种计算所有拉杆的最高奖励概率的蒙特卡洛采样方法】

  在实际中,通常用 Beta 分布对当前每个动作的奖励概率分布进行建模。具体来说,若某拉杆被选择了 k 次,其中 m 1 m_1 m1 次奖励为 1, m 2 m_2 m2 次奖励为 0,则该拉杆服从参数为 ( m 1 + 1 , m 2 + 1 ) (m_1+1,m_2+1) (m1+1,m2+1) Beta 分布。

新建 ThompsonSampling.py 文件,文件代码如下:

import numpy as np

from Solver import Solver


class ThompsonSampling(Solver):
    def __init__(self, bandit):
        super(ThompsonSampling, self).__init__(bandit)
        self._a = np.ones(self.bandit.K)
        self._b = np.ones(self.bandit.K)

    def run_one_step(self):
        samples = np.random.beta(self._a, self._b)
        k = np.argmax(samples)
        r = self.bandit.step(k)
        self._a[k] += r
        self._b[k] += (1 - r)
        return k

修改 Main.py 文件,文件代码如下:

import numpy as np
from matplotlib import pyplot as plt

from BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedy, DecayingEpsilonGreedy
from ThompsonSampling import ThompsonSampling
from UCB import UCB


def plot_results(solvers, solver_names):
    """输出解决方法的累积懊悔变化图"""
    for idx, solver in enumerate(solvers):
        time_list = range(len(solver.regrets))
        plt.plot(time_list, solver.regrets, label=solver_names[idx])
    plt.xlabel('Time Step')
    plt.ylabel('Cumulative regrets')
    plt.title('%d-arm bandit' % solvers[0].bandit.K)
    plt.legend()
    plt.show()


def apply_epsilon_greedy_1():
    np.random.seed(1)
    epsilon_greedy_solver = EpsilonGreedy(bandit, epsilon=0.01)
    epsilon_greedy_solver.run(5000)
    print('epsilon-贪婪算法的累积懊悔为:', epsilon_greedy_solver.regret)
    plot_results([epsilon_greedy_solver], ["EpsilonGreedy"])


def apply_epsilon_greedy_2():
    np.random.seed(1)
    epsilons = [1e-4, 0.01, 0.1, 0.25, 0.5]
    epsilon_greedy_solver_list = [EpsilonGreedy(bandit, epsilon=e) for e in epsilons]
    epsilon_greedy_solver_names = ['epsilon={}'.format(e) for e in epsilons]
    for epsilon_greedy_solver in epsilon_greedy_solver_list:
        epsilon_greedy_solver.run(50000)
    plot_results(epsilon_greedy_solver_list, epsilon_greedy_solver_names)


def apply_decaying_epsilon_greedy():
    np.random.seed(1)
    decaying_epsilon_greedy_solver = DecayingEpsilonGreedy(bandit)
    decaying_epsilon_greedy_solver.run(50000)
    print('epsilon 反比衰减的贪婪算法的累积懊悔为:', decaying_epsilon_greedy_solver.regret)
    plot_results([decaying_epsilon_greedy_solver], ["DecayingEpsilonGreedy"])


def apply_UCB():
    np.random.seed(1)
    c = 1  # 不确定性比重
    UCB_solver = UCB(bandit, c)
    UCB_solver.run(5000)
    print('上置信界算法累积懊悔为:', UCB_solver.regret)
    plot_results([UCB_solver], ["UCB"])


def apply_thompson_sampling():
    np.random.seed(1)
    thompson_sampling_solver = ThompsonSampling(bandit)
    thompson_sampling_solver.run(5000)
    print('汤普森采样算法累积懊悔为:', thompson_sampling_solver.regret)
    plot_results([thompson_sampling_solver], ["ThompsonSampling"])

apply_thompson_sampling()

运行 Main.py 文件,结果如下:

在这里插入图片描述

D:\RL\MAB\.venv\Scripts\python.exe D:\RL\MAB\Main.py 
随机生成了一个 10 臂的伯努利多臂老虎机
获奖概率最大的拉杆为 1 号,其获奖概率为 0.7203
汤普森采样算法累积懊悔为: 57.19161964443925

进程已结束,退出代码为 0
2.2.4 小结
算法累积懊悔与时间步的关系
ε-贪婪算法线性
ε-衰减贪婪算法次线性(对数)
上置信界算法次线性(对数)
汤普森采样算法次线性(对数)

第3章 马尔可夫决策过程

3.1 马尔可夫过程

过程介绍
随机过程在某时刻 t 的状态 S t S_t St 通常取决于 t 时刻之前的状态。状态 S t + 1 S_{t+1} St+1 的概率表示为: P ( S t + 1 ∣ S 1 , . . . , S t ) P(S_{t+1}|S_1,...,S_t) P(St+1S1,...,St)
马尔可夫过程某时刻 t 的状态只取决于上一个时刻 t-1 的状态。状态 S t + 1 S_{t+1} St+1 的概率表示为: P ( S t + 1 ∣ S t ) = P ( S t + 1 ∣ S 1 , . . . , S t ) P(S_{t+1}|S_t)=P(S_{t+1}|S_1,...,S_t) P(St+1St)=P(St+1S1,...,St)

  马尔可夫过程也被称为马尔可夫链,通常用元组 < S , P > <S,P> <S,P> 来描述,其中 S 是有限数量的状态集合,P 是状态转移矩阵。假设有 n 个状态,则 S = { s 1 , s 2 , . . . , s n } S=\{s_1,s_2,...,s_n\} S={s1,s2,...,sn} ,
P = [ P ( s 1 ∣ s 1 ) ⋯ P ( s n ∣ s 1 ) ⋮ ⋱ ⋮ P ( s 1 ∣ s n ) ⋯ P ( s n ∣ s n ) ] P=\begin{bmatrix} P(s_1|s_1) & \cdots & P(s_n|s_1) \\ \vdots & \ddots & \vdots\\ P(s_1|s_n) & \cdots & P(s_n|s_n) \end{bmatrix} P= P(s1s1)P(s1sn)P(sns1)P(snsn)
  矩阵 P 中第 i 行第 j 列元素 P ( s j ∣ s i ) = P ( S t + 1 = s j ∣ S t = s i ) P(s_j|s_i)=P(S_{t+1}=s_j|S_t=s_i) P(sjsi)=P(St+1=sjSt=si) 表示从状态 s i s_i si 转移到状态 s j s_j sj 的概率,称 P ( s ′ ∣ s ) P(s'|s) P(ss) 为状态转移函数。从某个状态出发,到达其他状态的概率和必须为 1 。即状态转移矩阵 P 的每一行和为 1 。

示例:

在这里插入图片描述

S = { S i , 1 ≤ i ≤ 6 }    状态转移矩阵    P = [ 0.9 0.1 0 0 0 0 0.5 0 0.5 0 0 0 0 0 0 0.6 0 0.4 0 0 0 0 0.3 0.7 0 0.2 0.3 0.5 0 0 0 0 0 0 0 1 ] S=\{S_i,1\le i \le 6\} \\ \; \\ 状态转移矩阵\;P= \begin{bmatrix} 0.9 & 0.1 & 0 & 0 & 0 & 0 \\ 0.5 & 0 & 0.5 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0.6 & 0 & 0.4 \\ 0 & 0 & 0 & 0 & 0.3 & 0.7 \\ 0 & 0.2 & 0.3 & 0.5 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 \\ \end{bmatrix} S={Si,1i6}状态转移矩阵P= 0.90.500000.10000.2000.5000.30000.600.500000.300000.40.701

3.2 马尔可夫奖励过程

3.2.1 定义

  马尔可夫奖励过程由 < S , P , r , γ > <S,P,r,\gamma> <S,P,r,γ> 构成,其中:

  • S 是有限状态的集合
  • P 是状态转移矩阵
  • r 是奖励函数, r ( s ) r(s) r(s) 是指转移到该状态时可以获得的奖励期望
  • γ \gamma γ 是折扣因子,取值范围为: [ 0 , 1 ] [0,1] [0,1] 。引入折扣因子是因为远期利益具有一定的不确定性,有时希望能尽快获得有些奖励,所以需要对远期利益打一些折扣。接近 1 则更关注长期的累积奖励,接近 0 则更关注短期奖励。
3.2.2 回报

  回报是指从状态 S t S_t St 开始,一直到终止状态,所有奖励的衰减之和。具体公式如下:
G t = ∑ k = 0 ∞ γ k R t + k G_t=\sum^{\infty}_{k=0}\gamma^kR_{t+k} Gt=k=0γkRt+k
  其中 R t R_t Rt 是指在时刻 t 获得的奖励。

示例:

在这里插入图片描述
【状态旁的数字表示进入该状态获得的奖励】

新建项目 MDP,项目结构如下:

在这里插入图片描述

在 MDP 目录下新建文件 MRP.py ,文件代码如下:

import numpy as np

np.random.seed(0)

P = [
    [0.9, 0.1, 0.0, 0.0, 0.0, 0.0],
    [0.5, 0.0, 0.5, 0.0, 0.0, 0.0],
    [0.0, 0.0, 0.0, 0.6, 0.0, 0.4],
    [0.0, 0.0, 0.0, 0.0, 0.3, 0.7],
    [0.0, 0.2, 0.3, 0.5, 0.0, 0.0],
    [0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
]
P = np.array(P)
rewards = [-1, -2, -2, 10, 1, 0]
gamma = 0.5


def compute_return(start, chain, gamma):
    G = 0
    for i in reversed(range(start, len(chain))):
        G = gamma * G + rewards[chain[i] - 1]
    return G


chain = [1, 2, 3, 6]
start = 0
G = compute_return(start, chain, gamma)
print('计算回报为:%s' % G)

运行 MRP.py 文件,运行结果如下:

D:\RL\MDP\.venv\Scripts\python.exe D:\RL\MDP\MRP.py 
计算回报为:-2.5

进程已结束,退出代码为 0
3.2.3 价值函数

3.3 马尔可夫决策过程

3.4 蒙特卡洛方法

3.5 占用度量

3.6 最优策略

第4章 动态规划算法

第5章 时序差分算法

第6章 Dyna-Q 算法

第二部分 强化学习进阶

第7章 DQN 算法

第8章 DQN 改进算法

第9章 策略梯度算法

第10章 Actor-Critic 算法

第11章 TRPO 算法

第12章 PPO 算法

第13章 DDPG 算法

第14章 SAC 算法

第三部分 强化学习前沿

第15章 模仿学习

第16章 模型预测控制

第17章 基于模型的策略优化

第18章 离线强化学习

第19章 目标导向的强化学习

第20章 多智能体强化学习入门

第21章 多智能体强化学习进阶

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1914044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(自用)gtest单元测试

gtest是Google的一套用于编写C测试的框架&#xff0c;可以运行在很多平台上&#xff08;包括Linux、Mac OS X、Windows、Cygwin等等&#xff09;。基于xUnit架构。支持很多好用的特性&#xff0c;包括自动识别测试、丰富的断言、断言自定义、死亡测试、非终止的失败、生成XML报…

跑GCN收敛实验时遇到的Python环境问题

错误1&#xff1a; 报错提示&#xff1a;No module named sklearn.utils.linear_assignment_ 原因&#xff1a;linear_assignment 函数从0.21开始被弃用了&#xff0c;并且将在0.23版本中移除。 解决方法&#xff1a;降低scikit-learn版本&#xff08;本人通过该方法解决&#…

从零开始开发视频美颜SDK:实现直播美颜效果

因此&#xff0c;开发一款从零开始的视频美颜SDK&#xff0c;不仅可以节省成本&#xff0c;还能根据具体需求进行个性化调整。本文将介绍从零开始开发视频美颜SDK的关键步骤和实现思路。 一、需求分析与技术选型 在开发一款视频美颜SDK之前&#xff0c;首先需要进行详细的需求…

自定义指令实现Element Plus分页组件内容样式修改

改之前是这样的 改之后是这样的 因为之前我也有写过文章讲解Vue2-ElementUI分页组件的样式修改。 ElementUI 分页组件内容样式修改https://blog.csdn.net/qq_54548545/article/details/139728064且通常情况下&#xff0c;一个项目若是大量使用到分页组件&#xff0c;咱们也不可…

MySQL语法笔记(补充版)

补充上一篇博客没涉及到的实用语法 MySQL语法笔记&#xff08;温习版&#xff09; 查看正在使用的数据库 SELECT DATABASE()查看时区 show VARIABLES like time_zone修改时区 timestamp类型存储的时间与MySQL数据库系统安装时所选的时区有关&#xff0c;在不同时区下查看的同…

【SVN的使用- SVN的基本命令-SVN命令简写-注意事项-解决冲突 Objective-C语言】

一、SVN的更新命令:update 1.服务器如果新建了一个文件夹,yuanxing,版本变成6了, 我现在本地还只有三个文件夹,版本5, 终端里边,我们敲一个svn update, 我这儿就多了一个yuanxing文件夹, 这个就是更新,就是把服务器最新的代码下载下来, 假设服务器上大家提交了这…

[CTF]-PWN:House of Cat堆题型综合解析

原理&#xff1a; 调用顺序&#xff1a; exit->_IO_wfile_jumps->_IO_wfile_seekoff->_IO_switch_to_wget_mode _IO_wfile_seekoff源码&#xff1a; off64_t _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) {off64_t result;off64_t delta, new…

基于ARM Cortex-M3单片机研发的国产指纹芯片 - P1032BF1

智能指纹锁的核心部件&#xff1a;主板、离合器、指纹采集器、密码技术、微处理器&#xff08;CPU&#xff09;、智能应急钥匙。作为指纹锁来说&#xff0c;重要的应该是指纹芯片。指纹锁是通过电子部件及机械部件的精密组合而生产出的安全产品。指纹锁的本质无非是安全、便捷、…

man手册的安装和使用

man手册 - HQ 文章目录 man手册 - HQ[toc]man手册的使用Linux man中文手册安装man中文手册通过安装包安装通过apt安装 配置man中文手册README使用说明配置步骤 man手册的使用 首先man分为八个目录&#xff0c;每个目录用一个数字表示 1.可执行程序2.系统调用3.库函数4.特殊文…

7.深度学习概述

深度学习概述 1. 线性回归1.1 线性回归一般表达式1.2 线性回归内积表达方式&#xff1a;1.3 多个样本时&#xff0c;线性回归的进一步表达&#xff1a;1.4 线性回归方程的解析1.5 线性回归就是求loss函数的最小值 2. 如何求函数最小值2.1 一个例子2.2 求导法——求最小值2.3 求…

CVE-2024-34351 漏洞复现

CVE-2024-34351&#xff0c;由Next.js异步函数createRedirectRenderResult导致的SSRF。 影响版本&#xff1a;13.4.0< Next.js < 14.1.1 参考文章&#xff1a; Next.js Server-Side Request Forgery in Server Actions CVE-2024-34351 GitHub Advisory Database Gi…

Ubuntu22.04.4 LTS系统/安装Anaconda【GPU版】

安装过程 1.wget命令行下载 下载Anaconda并保存文件至本地指定目录 wget -c https://repo.anaconda.com/archive/Anaconda3-2023.09-0-Linux-x86_64.sh -P ~/Downloads/anaconda3 查看是否下载好了 2.安装Anaconda 2.1 bash命令安装 bash后面是anaconda3下载好的路径 bash …

节点的真相:纠正大众对区块链安全概念的误解

​​发表时间&#xff1a;2024年4月25日 长期以来&#xff0c;人们都在对区块链及其基本原则进行讨论&#xff0c;但是只有“节点”这个概念被精准地定义&#xff0c;才能让我们穿越“去中心化”这个复杂概念的迷雾。在网络学的理论中&#xff0c;节点代表网络或图形中的一个实…

防火墙实验配置

实验要求 1&#xff0c;DMZ区内的服务器&#xff0c;办公区仅能在办公时间内&#xff08;9&#xff1a;00-18&#xff1a;00&#xff09;可以访问&#xff0c;生产区全天都能访问 2&#xff0c;生产区不允许访问互联网&#xff0c;办公区和游客区允许访问互联网 3&#xff0c;…

基于JavaSpringBoot+Vue+uniapp微信小程序校园宿舍管理系统设计与实现(论文7000字参考+源码+LW+部署讲解)

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…

【Android】基于 LocationManager 原生实现定位打卡

目录 前言一、实现效果二、定位原理三、具体实现1. 获取权限2. 页面绘制3. 获取经纬度4. 方法调用5. 坐标转换6. 距离计算7. 完整代码 前言 最近公司有个新需求&#xff0c;想要用定位进行考勤打卡&#xff0c;在距离打卡地一定范围内才可以进行打卡。本文将借鉴 RxTool 的 Rx…

nodejs实现文件的分片写入和读取

&#xff08;1&#xff09;创建 test.cjs 文件 &#xff08;2&#xff09;代码 const {readFileSync,writeFileSync} require(fs); const {dirname} require(path); const chunkSize 1024 * 8; // 切片大小 const path C:\\Users\\cat\\De…

高速电吹风方案介绍,多档温度风速调节,转速可达105000RPM

高速电吹风是这几年很火的一种电动小家电&#xff0c;能够在较短时间内完成头发干燥&#xff0c;减少对头发的热损伤。可以通过高速电机和风扇来产生高速风流&#xff0c;迅速将头发表面的水分吹干。高速电吹风通常配有多种档位风速和温度可以设置&#xff0c;用户可以根据需要…

vue中,图片在div中按照图片原来大小等比例显示

图片在div中按照图片原来大小等比例显示&#xff0c;可以保证web上显示的图片和实际图片形状一样&#xff0c;保留原始图片效果 实现代码如下&#xff1a; <div style"padding: 0; width:400px;height:400px;position: absolute;border: 1px solid #eff2f6;">…

学习笔记——动态路由——OSPF链路状态通告(LSA)

十、OSPF链路状态通告(LSA) 1、链路状态通告简介 (1)LAS概述 链路状态通告(Link State Advertisement&#xff0c;LSA)是路由器之间链路状态信息的载体。LSA是LSDB的最小组成单位&#xff0c;LSDB由一条条LSA构成的。是OSPF中计算路由的重要依据。 LSA用于向其它邻接OSPF路…