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

文章目录

  • 第一部分 强化学习基础
    • 第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 pltclass 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=Kdef step(self, k):if np.random.rand() < self.probs[k]:return 1else:return 0np.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 npclass Solver:"""多臂老虎机解决方案抽象类"""def __init__(self, bandit):self.bandit = banditself.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 NotImplementedErrordef run(self, num_steps):# 运行一定次数,num_steps为总运行次数for _ in range(num_steps):k = self.run_one_step()self.counts[k] += 1self.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 npfrom Solver import Solverclass EpsilonGreedy(Solver):def __init__(self,bandit,epsilon=0.01,init_prob=1.0):super(EpsilonGreedy,self).__init__(bandit)self.epsilon = epsilonself.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 pltfrom BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedydef 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 pltfrom BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedydef 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 npfrom Solver import Solverclass EpsilonGreedy(Solver):def __init__(self, bandit, epsilon=0.01, init_prob=1.0):super(EpsilonGreedy, self).__init__(bandit)self.epsilon = epsilonself.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 kclass 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 = 0def run_one_step(self):self.total_count += 1if 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 pltfrom BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedy, DecayingEpsilonGreedydef 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 npfrom Solver import Solverclass UCB(Solver):def __init__(self, bandit, c, init_prob=1.0):super(UCB, self).__init__(bandit)self.total_count = 0self.estimates = np.array([init_prob] * self.bandit.K)self.c = cdef run_one_step(self):self.total_count += 1ucb = 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 pltfrom BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedy, DecayingEpsilonGreedy
from UCB import UCBdef 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 npfrom Solver import Solverclass 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] += rself._b[k] += (1 - r)return k

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

import numpy as np
from matplotlib import pyplot as pltfrom BernoulliBandit import bandit
from EpsilonGreedy import EpsilonGreedy, DecayingEpsilonGreedy
from ThompsonSampling import ThompsonSampling
from UCB import UCBdef 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 npnp.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.5def compute_return(start, chain, gamma):G = 0for i in reversed(range(start, len(chain))):G = gamma * G + rewards[chain[i] - 1]return Gchain = [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://xiahunao.cn/news/3226387.html

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

相关文章

windows10 +VS2019环境下的PCL安装和配置

今天想做点云重建&#xff0c;千篇一律&#xff0c;PCL少不了。一路跑下来觉得PCL的安装和环境配置还挺麻烦的&#xff0c;比OpenCV真的麻烦很多&#xff0c;有点不想写详细安装和配置过程了&#xff0c;偷个懒&#xff0c;就转载一下大佬的文章吧&#xff0c;下面的博主们已经…

PostgreSQL 中如何处理数据的并发更新冲突解决?

文章目录 一、并发更新冲突的场景二、PostgreSQL 中的并发控制机制&#xff08;一&#xff09; 封锁机制&#xff08;二&#xff09; 事务隔离级别 三、并发更新冲突的解决方法&#xff08;一&#xff09; 重试机制&#xff08;二&#xff09; 使用乐观并发控制&#xff08;三&…

用这款免费爬虫神器,不用手动撸代码了!

很多人学习Python和我说是为了“爬虫”&#xff0c;爬虫的用处确实很丰富&#xff0c;如&#xff1a; 市场研究&#xff0c;了解竞争对手信息&#xff0c;爬虫收集舆论信息、产品动态。 价格分析&#xff0c;通过抓取不同平台商品价格&#xff0c;监测价格波动&#xff0c;…

PDManer使用教程及安装包

以下安装包版本比较低&#xff0c;用习惯了&#xff0c;需要高版本可以去官网下载 链接&#xff1a;https://pan.baidu.com/s/1Hj4zJ0UCcdk0YQTlteVCTQ?pwdv72v 提取码&#xff1a;v72v 使用教程 连接数据库 导入表信息 创建关系图 第一步 第二步 如果列显示不全 &#x…

【LLM大模型】机器学习导论(西瓜书)[推荐阅读]

哈喽啊大家&#xff0c;今天又来给大家推荐一本机器学习方面的书籍<机器学习西瓜书>。本书作为该领域的入门教材&#xff0c;在内容上尽可能涵盖机器学习基础知识的各方面。 为了使尽可能多的读者通过本书对机器学习有所了解&#xff0c;作者试图尽可能少地使用数学知识…

【内网渗透】MSF渗透阶段的常用指令笔记

目录 渗透阶段划分 msfvenom 常用参数 各平台生成payload命令 Meterpreter Meterpreter的常用命令 基本命令 常用命令 针对安卓手机的一些命令 针对Windows的一些命令 文件系统命令 生成木马反弹shell(以linux靶机为例) 木马生成 配置监控 攻击利用 辅助模块 怎…

QT TCP多线程网络通信

学习目标&#xff1a; TCP网络通信编程 学习前置环境 运行环境:qt creator 4.12 QT TCP网络通信编程-CSDN博客 Qt 线程 QThread类详解-CSDN博客 学习内容 使用多线程技术实现服务端计数器 核心代码 客户端 客户端&#xff1a;负责连接服务端&#xff0c;每次连接次数1。…

从零开始做题:MP3

题目 给出一个mp3文件 解题 右键->selection->save selection->另存为xxx.png即可 8750d5109208213f E:\逐鹿\MISC\tools\MP3Stego_1_1_19\MP3Stego>.\decode -X cipher.mp3 MP3StegoEncoder 1.1.19 See README file for copyright info Input file cipher.mp3…

秒懂设计模式--学习笔记(8)【结构型-组合模式】

目录 7、组合模式7.1 组合模式&#xff08;Composite&#xff09;7.2 叉树结构7.3 文件系统7.4 目录树展示7.5 自相似性的涌现7.6 组合模式的各角色定义7.7 组合 7、组合模式 7.1 组合模式&#xff08;Composite&#xff09; 是针对由多个节点对象&#xff08;部分&#xff0…

centos部署jar包

第一步&#xff1a; 将IDEA中的项目打包为jar,将这个jar文件放到centos服务器上的目录里&#xff0c;我在opt新建api目录&#xff0c;将jar文件放入&#xff0c;如下图&#xff1a; 第二步&#xff1a; 将需要读取的配置文件也放入此目录(其他目录也可以&#xff0c;和脚本中…

Thread类的start()方法和run()方法的区别

在Java多线程编程中&#xff0c;Thread类是一个非常重要的类&#xff0c;它提供了创建和管理线程的能力。对于初学者来说&#xff0c;理解Thread类的start()方法和run()方法之间的区别尤为重要。本文将深入探讨这两者之间的不同&#xff0c;帮助读者更好地掌握Java多线程编程的…

web端的vscode编辑器

下载code-server到本地 略 参考 https://blog.csdn.net/kfashfasf/article/details/137110668 运行code-server 到用户目录下设置 vim ~/.config/code-server/config.yaml . bind-addr: 0.0.0.0:8080 auth: password password: xxxxxx cert: false运行 [centosamazon22 ~…

中职网络安全wire0077数据包分析

从靶机服务器的FTP上下载wire0077.pcap&#xff0c;分析该文件&#xff0c;找出黑客入侵使用的协议&#xff0c;提交协议名称 SMTP 分析该文件&#xff0c;找出黑客入侵获取的zip压缩包&#xff0c;提交压缩包文件名 DESKTOP-M1JC4XX_2020_09_24_22_43_12.zip 分析该文件&…

使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-滚动背景(四)

文章目录 开发思路开发思路 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击&#xff08;一&#xff09; 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-激光组件&#xff08;二&#xff09; 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-飞船动画&#xff08…

pytorch-RNN实战-正弦曲线预测

目录 1. 正弦数据生成2. 构建网络3. 训练4. 预测5. 完整代码6. 结果展示 1. 正弦数据生成 曲线如下图&#xff1a; 代码如下图&#xff1a; 50个点构成一个正弦曲线随机生成一个0~3之间的一个值&#xff08;随机的原因是防止每次都从相同的点开始&#xff0c;50个点的正弦曲…

JavaSE 面向对象程序设计进阶 IO流 字节流详解 抛出异常

input output 像水流一样读取数据 存储和读取数据的解决方案 内存中数据不能永久化存储 程序停止运行 数据消失 File只能对文件本身进行操作 不能读写文件里存储的数据 读写数据必须要有IO流 可以把程序中的数据保存到文件当中 还可以把本地文件中的数据读取到数据当中 分…

白酒营销策划全攻略:从市场调研到执行落地的实战指南!

为白酒品牌做营销策划&#xff0c;那可得像给自家的孩子挑衣服一样&#xff0c;得量身定制&#xff0c;得考虑孩子的身材、喜好&#xff0c;还得看看衣服的款式和布料。 这里可以分享一点自己多年的实战干货给你&#xff0c;希望对你有所帮助。 首先&#xff0c;得做好“侦查…

【常见开源库的二次开发】一文学懂CJSON

简介&#xff1a; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式。它基于JavaScript的一个子集&#xff0c;但是JSON是独立于语言的&#xff0c;这意味着尽管JSON是由JavaScript语法衍生出来的&#xff0c;它可以被任何编程语言读取和生成…

CentOS7系统上安装MySQL8.0(rpm-bundle.tar)详细过程

一、MySQL官网下载安装包 1.进入官网MySQL :: Download MySQL Community Server 2.查看自己的版本和架构 uname -mcat /etc/redhat-release 3.选择对应版本并下载 4.查看linux自带的mariadb数据库&#xff0c;有就卸载掉。 rpm -qa | grep mariadbrpm -e mariadb-libs…

【卡尔曼滤波】高斯白噪声

生成高斯白噪声并将其应用于信号处理 生成高斯白噪声并将其应用于信号处理 #以下是一个生成高斯白噪声并将其应用于信号处理的示例代码:import numpy as np import matplotlib.pyplot as plt import matplotlib.font_manager ## not work#notice matplotlibrc is a file, not…