多臂老虎机

多臂老虎机

有n根拉杆的的老虎机,每根拉杆获得奖励(值为1)的概率各不相同。

期望奖励更新
Q k = 1 k ∑ i = 1 k r i = 1 k ( r k + ∑ i = 1 k − 1 r i ) = 1 k ( r k + k Q k − 1 − Q k − 1 ) = Q k − 1 + 1 k [ r k − Q k − 1 ] Q_k=\frac 1k \sum^{k}_{i=1}r_i\\ =\frac 1k (r_k+\sum^{k-1}_{i=1}r_i)\\ =\frac 1k( r_k+kQ_{k-1}-Q_{k-1})\\ =Q_{k-1}+\frac 1k[r_k-Q_{k-1}] Qk=k1i=1kri=k1(rk+i=1k1ri)=k1(rk+kQk1Qk1)=Qk1+k1[rkQk1]
累计懊悔:

​ 至少存在一根拉杆,它的期望奖励不小于拉动其他任意一根拉杆,设最优期望为 Q ∗ = m a x a ∈ A Q ( a ) Q^*=max_{a\in A}Q(a) Q=maxaAQ(a),在此基础上,引入懊悔概念,被定义为当前的收益与最优期望的插值,即 R ( a ) = Q ∗ − Q ( a ) R(a)=Q^*-Q(a) R(a)=QQ(a),累计懊悔 σ R = ∑ t = 1 T R ( a t ) \sigma_R=\sum^T_{t=1}R(a_t) σR=t=1TR(at),则多臂老虎机可等价为最小化累积期望。

基本框架

多臂老虎机的基本框架如下

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的数作为概率,获奖积1分,没获奖0分self.best_idx = np.argmax(self.probs)  # 获奖概率最大的拉杆self.best_prob = self.probs[self.best_idx]  # 最大获奖概率self.K = Kdef step(self, K):# 进行一步,根据选择的第k号拉杆获奖的概率进行返回if np.random.rand() < self.probs[K]:return 1else:return 0np.random.seed(1)  # 设置一样的随机种子,使得实验可重复
K = 10
bandit_10_arm = BernoulliBandit(K)
print("随机生成了一个%d臂伯努利老虎机" % K)
print("获奖概率最大的拉杆为%d号,其获奖概率为%.4f" % (bandit_10_arm.best_idx, bandit_10_arm.best_prob))class 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 NotImplementedError  # ?问下gptdef run(self, num_steps):# 运行一定次数for _ in range(num_steps):k = self.run_one_step()self.counts[k] += 1self.actions.append(k)self.actions.append(k)self.update_regret(k)def plot_results(solvers, solver_names):# 输入的solvers是一个列表,每个元素是一个特定策略,solver_names也是一个列表,存储每个策略的名称for idx, solver in enumerate(solvers):
"""enumerate() 函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般在循环中使用。此处将索引存在idx,具体的策略存在solver中"""time_list = range(len(solver.regrets))  # 生成一个包含从 0 到 solver.regrets 的大小减去 1 的整数序列。plt.plot(time_list, solver.regrets, label=solver_names[idx])plt.xlabel("Time steps")plt.ylabel("Cumulative regrets")plt.title("%d-armed bandit" % solvers[0].bandit.K)plt.legend()  # 用于添加图例到 Matplotlib 图表中的函数,即使用label标签标记的。plt.show()

​ 对于多臂老虎机的决策,有如下方法

ϵ \epsilon ϵ-贪婪算法

​ 这个算法设置一个随机概率 ϵ \epsilon ϵ,每次做决策时,有 1 − ϵ 1-\epsilon 1ϵ的概率按已有经验做出最优决策,在这个问题中,即在拉动过的杆中选出最优的,以概率 ϵ \epsilon ϵ随机选择一根拉杆。

​ 本例中先选择 ϵ = 0.01 , T = 5000 \epsilon =0.01,T=5000 ϵ=0.01,T=5000

class EpsilonGreedy(Solver):"""epsilon贪婪算法,需要继承Solver类"""def __init__(self, bandit, epsilon=0.01, init_prob=1.0):super(EpsilonGreedy, self).__init__(bandit)  # 调用父类的构造函数,用bandit作为参数self.epsilon = epsilonself.estimates = np.array([init_prob] * self.bandit.K)  # 初始化所有拉杆的期望奖励估值,设置为一样的?def run_one_step(self):# 以贪婪算法运行一步if np.random.rand() < 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  # 返回选择的杆的编号np.random.seed(1)
epsilon_greedy_solver = EpsilonGreedy(bandit_10_arm, epsilon=0.01)
epsilon_greedy_solver.run(5000)
print('epsilon-贪婪算法的累计懊悔为:', epsilon_greedy_solver.regret)
plot_results([epsilon_greedy_solver], ["EpsilonGreedy"])

在这里插入图片描述

​ 实际上,尝试次数越多,越不需要冒险去探险,因为这无疑会降低收益,那么我们希望 ϵ \epsilon ϵ随时间逐渐变小。即 ϵ t = 1 t \epsilon_t = \frac 1t ϵt=t1,一般使用随时间衰减的贪婪算法:

class DecayingEpsilonGreedy(Solver):"""epsilon值随时间衰减的贪婪算法,需要继承Solver类"""def __init__(self, bandit, init_prob=1.0):super(DecayingEpsilonGreedy, self).__init__(bandit)  # 调用父类的构造函数,用bandit作为参数self.estimates = np.array([init_prob] * self.bandit.K)  # 初始化所有拉杆的期望奖励估值,设置为一样的?self.total_count = 0def run_one_step(self):# 以贪婪算法运行一步self.total_count += 1if np.random.rand() < 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  # 返回选择的杆的编号np.random.seed(1)
decaysing_epsilon_greedy_solver = DecayingEpsilonGreedy(bandit_10_arm)
decaysing_epsilon_greedy_solver.run(5000)
print('epsilon值衰减的-贪婪算法的累计懊悔为:', decaysing_epsilon_greedy_solver.regret)
plot_results([decaysing_epsilon_greedy_solver], ["DecayingEpsilonGreedy"])

在这里插入图片描述

上置信界算法(UCB)

​ 在探索时,我们总会有这样的一种想法,如果第1根拉杆只被拉动过1次,但奖励为0,第2根被拉动过很多次,我们对它的奖励分布已经有了比较确定的把握,或许我们更愿意尝试拉动第一根拉杆,可能他的收益更高。为了定量的描述这种“潜藏“的更优解,引入了不确定性度量 U ( a ) U(a) U(a),它会随着一个动作被尝试次数的增加而减小。

​ 那么我们可以使用一种基于不确定性的策略来综合考虑现有的期望奖励估值和不确定性,其核心问题是如何估计不确定性。

霍夫丁不等式

​ 令 X 1 , ⋯ , X n X_1,\cdots,X_n X1,,Xn n n n个独立同分布的随机变量,取值范围为 [ 0 , 1 ] [0,1] [0,1],若经验期望为 x ‾ = 1 x ∑ j = 1 n X j \overline{x}=\frac 1x\sum^n_{j=1}X_j x=x1j=1nXj,则有
P ( E [ X ] ≥ x ‾ t + u ) ≤ e − 2 n u 2 P(E[X]\ge \overline{x}_t +u)\le e^{-2nu^2} P(E[X]xt+u)e2nu2

期望的奖励上界

​ 在这个例子中,经验期望就是 Q ^ ( a t ) \hat{Q}(a_t) Q^(at),将 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,其中 N ( a t ) N(a_t) N(at)表示拉动某一编号杆的次数。根据霍夫丁不等式, 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 p p很小时,以很大概率成立,那么我们可以认为 Q ^ ( a t ) + U ^ ( a t ) \hat{Q}(a_t)+\hat{U}(a_t) Q^(at)+U^(at)便是期望的奖励上界。

​ 此时,UCB算法选取上界最大的动作,即 a t = a r g m a x a ∈ A [ Q ^ ( a ) + U ^ ( a ) ] a_t = arg\ max_{a\in A}[\hat{Q}(a)+\hat{U}(a)] at=arg maxaA[Q^(a)+U^(a)]

​ 其中 U ^ ( a t ) = − l o g p 2 N ( a t ) \hat{U}(a_t)=\sqrt{\cfrac{-log\ p}{2N(a_t)}} U^(at)=2N(at)log p ,也就是说,设定一个概率 p p p后,就可计算了。

​ 总的来说,UCB算法在每次决策前,都会估计每根杆的期望上界,使得拉动每根杆的期望奖励只有一个较小的概率 p p p超过上界,并选取最优可能获得最大期望奖励的拉杆。

UCB算法的代码实现

​ 容易发现的是,随着时间的增长,我们将对期望有着越来越确定的把握,那么 p p p的设置也应该是随时间增长减少的,则设 p = 1 t p=\frac 1t p=t1

​ 对于 U ^ ( a t ) \hat{U}(a_t) U^(at),我们在分母加上常数1,避免出现分母为0的情况,则 U ^ ( a t ) = l o g t 2 ( N ( a t ) + 1 ) \hat{U}(a_t)=\sqrt{\frac{log t}{2(N(a_t)+1)}} U^(at)=2(N(at)+1)logt

​ 为了控制不确定性的比重,引入系数 c c c,此时, 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=arg maxaA[Q^(a)+cU^(a)]

class UCB(Solver):# UCB算法,继承Solver类def __init__(self, bandit, coef, init_prob=1.0):super(UCB, self).__init__(bandit)self.total_count = 0  # 时间计数tself.estimates = np.array([init_prob] * self.bandit.K)  # 一样的初始化期望self.coef = coefdef run_one_step(self):self.total_count += 1ucb = self.estimates + self.coef * np.sqrt(np.log(self.total_count) / (2 * (self.counts + 1)))  # 计算上置信界# np.log()默认以e为底,以其他为底可使用换底公式k = np.argmax(ucb)  # 选出上置信界最大的拉杆r = self.bandit.step(k)self.estimates[k] += 1. / (self.counts[k] + 1) * (r - self.estimates[k])return knp.random.seed(1)
coef = 0.7  # 不确定性权重的参数
UCB_solver = UCB(bandit_10_arm, coef)
UCB_solver.run(5000)
print("上置信界算法的累积懊悔为:", UCB_solver.regret)
plot_results([UCB_solver], ["UCB"])

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习笔记 PostgresML教程:使用SQL进行机器学习

机器学习的基本做法是将数据转移到模型的环境中进行训练。由于今天的数据库比机器学习模型大好多个数量级,所以PostgresML的思路是,如果我们将模型引入数据集不是会容易得多吗? PostgresML 是一个建立在流行的 PostgreSQL 数据库之上的综合机器学习平台。它引入了一种称为“…

嵌入式学习-通用定时器

简介 框图介绍 时钟选择 计数器部分 输入捕获和输出比较框图 嵌入式学习全文参考&#xff08;小向是个der&#xff09;做笔记&#xff1a;https://blog.csdn.net/qq_41954556/article/details/129735708

Linux第四节--常见的指令介绍集合(持续更新中)

点赞关注不迷路&#xff01;本节涉及初识Linux第四节&#xff0c;主要为常见的几条指令介绍。 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1f44d;&#x1f3fb; 收藏 ✨ 加关注&#x1f440; 期待与你共同进步! 1. more指令 语法&#xff1a;more [选项][文件]…

r语言数据分析案例-北京市气温预测分析与研究

一、选题背景 近年来&#xff0c;人类大量燃烧煤炭、天然气等含碳燃料导致温室气 体过度排放&#xff0c;大量温室气体强烈吸收地面辐射中的红外线&#xff0c;造 成温室效应不断累积&#xff0c;使得地球温度上升&#xff0c;造成全球气候变暖。 气象温度的预测一直以来都是…

Linux修炼之路之yum和vim编辑器

目录 一&#xff1a;Linux软件包管理器yum 二&#xff1a;vim编辑器 vim的三种模式及互相转换 命令模式 底行模式 三&#xff1a;普通用户的sudo指令(修改信任名单) 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 一&#xff1a…

基于Java的俄罗斯方块游戏的设计与实现

关于俄罗斯方块项目源码.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89300281 基于Java的俄罗斯方块游戏的设计与实现 摘 要 俄罗斯方块是一款风靡全球&#xff0c;从一开始到现在都一直经久不衰的电脑、手机、掌上游戏机产品&#xff0c;是一款游戏规则简单…

gin导出excel文件

go可以通过excelize 包实现对excel的操作 "github.com/xuri/excelize/v2"导出示例 service层 批量导出数据的&#xff0c;我们可以在dao层中返回一个切片。在service中新建一个excelize对象&#xff0c;单独设置表头。遍历切片往excelize上修改即可。 func (s *S…

76岁林子祥升级做爷爷,亲自为孙女取名

林子祥与前妻吴正元的儿子&#xff0c;现年39岁的林德信入行以来绯闻不少&#xff0c;自与圈外女友Candace拍拖后便修心养性&#xff0c;去年他已经低调与拍拖5年多Candace完婚&#xff0c;正式步入人生另一阶段。 昨日&#xff08;5月12日&#xff09;林德信借母亲节这个温馨日…

Amesim基础篇-表格类型设置与读取

前言 在Amesim仿真中,不可避免需要应用到表格。如新能源动力电池中内阻、充电倍率的调取,压缩机的机械效率、容积效率等,水泵的效率,管路的压降等等。本文将介绍如何对表格类型的选择与参数输入。 1 进入表格设置界面 如下图所示,在Amesim界面的右上角Table Editor进入…

leetcode.K站中转(python)

开始准备用dfs深度搜索&#xff0c;发现n100&#xff0c;dfs可能会超时&#xff0c;即使用了剪枝。 class Solution:def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:length k 2ans float(inf)rec []vis [True]*n…

百望云钉钉:重塑财务智能化管理,助力企业实现数字化飞跃

近年来&#xff0c;数字技术正在深刻改变着企业生产方式和组织模式&#xff0c;企业面连着业务流程再造、经营模式创新等一系列建设挑战。 其中&#xff0c;财务部门从价值守护走向价值创造的过程中&#xff0c;展现出对企业经营与业务发展的巨大影响力。叠加金税四期税务改革&…

【JS面试题】原型原型链

一、面试真题展示&#xff1a; 1. 如何准确判断一个变量是不是数组&#xff1f; ① 使用instanceof进行判断&#xff1a;a instanceof Array ② 使用Array.isArray()进行判断&#xff1a;Array.isArray(a) 2. 手写一个简易的jQuery&#xff0c;考虑插件和扩展性&#xff1f; …