强化学习——多臂老虎机问题(MAB)【附python代码】

文章目录

  • 一、问题描述
    • 1.1 问题定义
    • 1.2 形式化描述
    • 1.3 累积懊悔
    • 1.4 估计期望奖励
  • 二、解决方法
    • 2.1 ϵ-贪婪算法
    • 2.2 上置信界算法
    • 2.3 汤普森采样算法
    • 2.4 小结

一、问题描述

1.1 问题定义

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

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

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

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

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 获得的奖励。

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 问题等价于最小化累积懊悔

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)

配置 numpy 和 matplotlib 模块

访问文章:配置 numpy 和 matplotlib 模块

二、解决方法

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 上置信界算法

  对于多臂老虎机来说,一根拉杆的探索次数较少,它的不确定性就很高。不确定越高,它具有的探索价值就越大。为此,引入不确定性度量 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.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.4 小结

算法累积懊悔与时间步的关系
ε-贪婪算法线性
ε-衰减贪婪算法次线性(对数)
上置信界算法次线性(对数)
汤普森采样算法次线性(对数)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【JavaScript 算法】贪心算法:局部最优解的构建

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、贪心算法的基本概念贪心算法的适用场景 二、经典问题及其 JavaScript 实现1. 零钱兑换问题2. 活动选择问题3. 分配问题 三、贪心算法的应用四、总结 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种逐步构建解…

【前端6*】表格-表单2(弹窗在父组件)父子组件调用 vue element-ui

vue element-ui 中表单弹框的使用 写在最前面一、完整代码1、&#xff08;子组件&#xff09;E:\ui\参考代码\demo-new\src\components\detail.vue2、&#xff08;父组件&#xff09;E:\ui\参考代码\demo-new\src\views\Home.vue 二、小结 &#x1f308;你好呀&#xff01;我是…

Qt Style Sheets-入门

Qt 样式表是一种强大的机制&#xff0c;允许您自定义小部件的外观&#xff0c;这是在通过子类化QStyle已经可行的基础上的补充。Qt 样式表的概念、术语和语法在很大程度上受到 HTML级联样式表 (CSS)的启发&#xff0c;但适用于小部件的世界。 概述 样式表是文本规范&#xff0…

手机数据恢复技巧:适用于 Android 的恢复应用程序

发现自己意外删除了 Android 设备上的照片&#xff0c;这让人很痛苦。这些照片可能是值得纪念的文件&#xff0c;会让您想起一些难忘的回忆。删除它们后&#xff0c;您知道如何恢复它们。在这种情况下&#xff0c;您需要使用 Android 的照片恢复应用程序。 无论您需要直接从 A…

【Python基础教程】制作一个宿舍管理系统,数据库宿舍管理系统代码!(完整版,附源码)

今天我们一起学习一个新的小案例——宿舍管理系统。主要涉及列表、字典的初始化、增加、删除、修改和查询操作&#xff0c;以及函数的定义和调用。 一、需求&#xff1a; 有操作指引界面&#xff0c;显示操作号 能添加一个新的入住学生信息&#xff0c;包括学生姓名、宿舍号床…

蓝桥杯14小白月赛题解

直接输出pi/ti,for遍历 #include <iostream> using namespace std; #define int long long int a,b,c ; double t1.00; signed main() {cin>>a;int an0;for(int i1;i<a;i){cin>>b>>c;if(t>c*1.00/b){tc*1.00/b;ani;} }cout<<an<<e…

搭建hadoop+spark完全分布式集群环境

目录 一、集群规划 二、更改主机名 三、建立主机名和ip的映射 四、关闭防火墙(master,slave1,slave2) 五、配置ssh免密码登录 六、安装JDK 七、hadoop之hdfs安装与配置 1)解压Hadoop 2)修改hadoop-env.sh 3)修改 core-site.xml 4)修改hdfs-site.xml 5) 修改s…

使用GPT3.5,LangChain,FAISS和python构建一个本地知识库

引言 介绍本地知识库的概念和用途 在现代信息时代&#xff0c;我们面临着海量的数据和信息&#xff0c;如何有效地管理和利用这些信息成为一项重要的任务。本地知识库是一种基于本地存储的知识管理系统&#xff0c;旨在帮助用户收集、组织和检索大量的知识和信息。它允许用户…

深度学习驱动智能超材料设计与应用

在深度学习与超材料融合的背景下&#xff0c;不仅提高了设计的效率和质量&#xff0c;还为实现定制化和精准化的治疗提供了可能&#xff0c;展现了在材料科学领域的巨大潜力。深度学习可以帮助实现超材料结构参数的优化、电磁响应的预测、拓扑结构的自动设计、相位的预测及结构…

软件测试——非功能测试

工作职责&#xff1a; 1.负责产品系统测试&#xff0c;包括功能测试、性能测试、稳定性测试、用户场景测试、可靠性测试等。 2.负责测试相关文档的编写&#xff0c;包括测试计划、测试用例、测试报告等。 3.负责自动化测试框架、用例的维护。 岗位要求&#xff1a; 1.熟练…

数据可视化在智慧医疗中的重要应用

在现代智慧医疗的推动下&#xff0c;数据可视化技术正日益成为医疗领域的重要工具。通过将复杂的医疗数据转换为直观的图表和图形&#xff0c;数据可视化不仅提升了医疗服务的效率&#xff0c;还极大地改善了患者的就医体验。 在智慧医疗中&#xff0c;数据可视化首先在电子病历…

知识图谱和 LLM:利用Neo4j驾驭大型语言模型(探索真实用例)

这是关于 Neo4j 的 NaLLM 项目的一篇博客文章。这个项目是为了探索、开发和展示这些 LLM 与 Neo4j 结合的实际用途。 2023 年,ChatGPT 等大型语言模型 (LLM) 因其理解和生成类似人类的文本的能力而风靡全球。它们能够适应不同的对话环境、回答各种主题的问题,甚至模拟创意写…

实时系统Preempt RT与Xenomai之争!谁更主流,谁更实时

版权声明&#xff1a;本文主要内容基于“北京盟通科技有限公司”授权提供的文件&#xff0c;由“创龙科技”进行整理得出。感谢“盟通科技”的慷慨支持&#xff0c;让更多人了解Linux系统的“实时拓展”选择知识。 选择争论一直存在 大家知道EtherCAT是实时现场总线技术&…

Java中使用加密盐

0 前言 众所周知&#xff0c;密码肯定不能用明文存储。 之前一直使用MD5进行加密&#xff0c;现在才知道有彩虹表这回事。所以记录一下对应的处理方式&#xff1a;加密盐。 1 彩虹表 例如用MD5加密&#xff0c;随便没法破解&#xff0c;但是有些常用的字符被收集到彩虹表里…

OSU!题解(概率dp)

题目&#xff1a;OSU! - 洛谷 思路&#xff1a; 设E()表示截止到i所获得的分数&#xff1b; 对于到i点的每一个l&#xff0c;如果第i1点为1&#xff0c;那么会新增分数3*l^23*l1; 就有递推公式方程&#xff1a; E()E()p[i1]p*(3*l^23*l1);(p代表截止到i获得长度l的概率)&a…

关于mybatis中语法的错误记录

大家注意再写mybatis时候的逗号&#xff0c;虽然不起眼&#xff0c;但是会一直报错&#xff0c;最后一个字段不需要逗号&#xff0c;其余字段全部需要逗号。

【个人笔记】685. 冗余连接 II 的解释(并查集)

一棵树有n个点和n条边&#xff0c;返回一条能删除的边&#xff0c;使得剩下的图是有 n 个节点的有根树。 解释&#xff1a; 注意不冗余的有根树的特性&#xff01;**根节点入度为0&#xff0c;其余结点只有一个入度&#xff01;**所以冗余的两种情况如下&#xff1a; &#xff…

Vue3项目基于Axios封装request请求

在 Vue 3 的项目开发中&#xff0c;使用 Axios 进行 HTTP 请求是非常常见的作法&#xff0c;为了更方便开发者更高效的进行代码编写和项目的维护&#xff0c;可以通过再次封装 Axios 来实现。 在本文中&#xff0c;博主将详细指导你如何在自己的 Vue 3 项目中使用 Axios 二次封…

Vue学习---vue cli 项目创建

使用的编辑工具webStorm 创建例子: hello vue create hello 选择 vue3 进行创建 运行 npm run serve 测试访问&#xff1a;http://localhost:8080 改动内容重新编译&#xff1a; npm run build dist 目录就是编译后的可运行内容

客流统计系统优化景区服务流程,增强游客满意度

在当今旅游业蓬勃发展的时代&#xff0c;景区面临着越来越多的挑战和机遇。如何提供更优质、更高效的服务&#xff0c;满足游客日益增长的需求&#xff0c;成为了景区管理者们关注的焦点。客流统计系统作为一种创新的技术手段&#xff0c;正逐渐成为优化景区服务流程、增强游客…