Bandit算法学习[网站优化]04——UCB(Upper Confidence Bound) 算法

news2024/12/28 3:22:30

Bandit算法学习[网站优化]04——UCB(Upper Confidence Bound) 算法

参考资料

  1. White J. Bandit algorithms for website optimization[M]. " O’Reilly Media, Inc.", 2013.
  2. https://github.com/johnmyleswhite/BanditsBook
  3. UCB算法原理及其在星际争霸比赛中的应用
  4. Auer P, Cesa-Bianchi N, Fischer P. Finite-time analysis of the multiarmed bandit problem[J]. Machine learning, 2002, 47(2): 235-256.

实验环境:jupyter python 3.7

UCB(Upper Confidence Bound - 置信上限)就是以均值的置信上限为来代表它的预估值。

一、UCB算法介绍

到目前为止,我们所介绍的算法有一个系统性的弱点:它们没有跟踪对任何可用臂的了解程度。这些算法只注意从臂中获得了多少奖励。我们可以通过使用一个不仅关注what it knows,而且关注how much it knows的算法来做得更好。而本文中介绍的算法UCB就是这样做的。

让我们回顾一下epsilon-Greedy和Softmax算法,并从更抽象的角度来看待它们。epsilon-Greedy算法和Softmax算法都具有以下属性:

  • 算法默认选择当前具有最高估计值的臂。

  • 算法有时会决定探索并选择一个当前看起来不是最好的选项

    • epsilon-Greedy算法通过完全随机地从所有臂中选择来进行探索。用概率ε作为这些随机的探索性决策之一。

    • Softmax算法通过从所有可用的臂中随机选择,其概率与每个臂的估计值成正比。如果其他臂明显比最好的武器差,就会以很低的概率选择它们。如果这些臂都有类似的价值,它们被选择的概率几乎相同

  • 可以使用退火法将这两种算法设置为随时间动态地修改它们的基本参数。

UCB算法对上述属性做出的改进为:它可以由我们选择的臂的估计值的置信度(confidence)来驱动探索。

置信区间是指由样本统计量所构造的总体参数的估计区间。

置信区间的解释: 机器学习笔记 - 什么是置信区间?

那为什么跟踪臂估计值的置信度十分重要?因为从臂收获到的奖励是有噪声的(noisy)。如果我们使用过去对一个臂的经验,那么任何臂的估计值总是真实值的一个有噪声的估计。epsilon-Greedy算法和Softmax算法对这种噪声不具有鲁棒性。简而言之,epsilon-Greedy和Softmax算法很容易被一些负面的经验所误导。这是由于它们使用了随机化,不过可以在以后弥补这一缺陷。而UCB采取的是一种非常不同的方法。

UCB要求我们在评估所有武器的估计价值时跟踪置信度,以避免‘被欺骗’。要做到这一点,需要有衡量我们对每只臂了解多少的指标:可以利用算法中的counts字段。

在本书中,我们将只关注UCB系列中的一种算法——UCB1算法。

除了追踪置信度,UCB还有其他特点:

  • 不使用随机性。

  • 不需要设置相关参数,如前面两种算法的epsilontemperature

二、UCB算法的原理

UCB1的算法伪代码如下:

Repeat:

  • ​ if n i = 0 n_i = 0 ni=0 for some i ∈ 1... K i\in 1...K i1...K play i i i

  • ​ else play i = argmax { μ ^ j + 2 log ⁡ N n j   ,    j = 1... K } i = \text{argmax}\{\hat\mu_j + \sqrt{\frac{2\log N}{n_j}}\ ,\ \ j=1...K\} i=argmax{μ^j+nj2logN  ,  j=1...K}

  • ​ let r r r be the associated reward

  • ​ Update n i n_i ni and μ ^ i \hat\mu_i μ^i

    • μ ^ i : = 1 n i + 1 × ( n i μ i + r ) \hat\mu_i :=\frac{1}{n_i+1}\times (n_i\mu_i+r) μ^i:=ni+11×(niμi+r)

    • n i : = n i + 1 n_i:=n_i +1 ni:=ni+1

  • N : = N + 1 N:=N+1 N:=N+1

各个参数的意义如下:

  • n i n_i ni:第 i i i个臂被拉的次数。

  • K K K:臂的数量

  • μ ^ i \hat\mu_i μ^i:第 i i i个臂的平均奖励

  • N N N:所有臂拉的次数之和

  • r r r:拉第 i i i个臂获得的奖励

其中置信度为 1 − 2 N 1-\frac{2}{N} 1N2,置信区间上限为 μ ^ j + 2 log ⁡ N n j \hat\mu_j + \sqrt{\frac{2\log N}{n_j}} μ^j+nj2logN

对于多个赌博机而言,给定置信度比如0.95,在同一个置信度的水平,选择最大的上置信界最大的作为选择策略。

在相同的置信度下,策略的选择由两部分组成,一部分为每个赌博机目前位置的平均收益,另外一部分为赌博机尝试次数反比例函数,因此UCB算法不仅考虑平均收益而且考虑尝试次数,相同平均收益的情况下,尝试次数少的赌博机更受到青睐,即UCB算法取上置信界,即乐观主义者(用较少的探索次数得到相同的收益,自信该赌博机在后面的探索中会得到更高的收益)

三、UCB算法的实现

使用python编写,实现如下:

import math


def index_max(x):
    """  
    获取向量x的最大值的索引
    """
    m = max(x)
    return x.index(m)


class UCB1():
    def __init__(self, counts, values):
        self.counts = counts
        self.values = values
        return

    def initialize(self, n_arms):
        self.counts = [0 for col in range(n_arms)]
        self.values = [0.0 for col in range(n_arms)]
        return

    def select_arm(self):
        n_arms = len(self.counts)
        # 确保所有的臂都至少玩了一次
        # 从而可以对所有可用的臂有一个初始化的了解
        for arm in range(n_arms):
            if self.counts[arm] == 0:
                return arm
        ucb_values = [0.0 for arm in range(n_arms)]
        total_counts = sum(self.counts)
        for arm in range(n_arms):
            # 使用置信区间上界
            # 置信度为1-2/total_counts
            bonus = math.sqrt((2 * math.log(total_counts)) /
                              float(self.counts[arm]))
            ucb_values[arm] = self.values[arm] + bonus

        return index_max(ucb_values)

    def update(self, chosen_arm, reward):
        self.counts[chosen_arm] = self.counts[chosen_arm] + 1
        n = self.counts[chosen_arm]

        value = self.values[chosen_arm]
        new_value = ((n - 1) / float(n)) * value + (1 / float(n)) * reward
        self.values[chosen_arm] = new_value
        return

对该算法进行评估,跟踪每个时间点的平均奖励:

import random
import numpy as np
import matplotlib.pyplot as plt


class BernoulliArm():
    def __init__(self, p):
        self.p = p

    def draw(self):
        if random.random() > self.p:
            return 0.0
        else:
            return 1.0


def get_cumulative_reward(algo, arms, num_sims, horizon):

    result = []

    for sim in range(num_sims):
        cumulative_rewards = [0.0 for i in range(horizon)]
        algo.initialize(len(arms))
        for t in range(horizon):
            t = t + 1
            index = t - 1

            # 选择臂
            chosen_arm = algo.select_arm()

            # 模拟拉动臂的结果
            reward = arms[chosen_arm].draw()

            # 记录算法收到的奖励金,然后调用更新
            if t == 1:
                cumulative_rewards[index] = reward
            else:
                cumulative_rewards[index] = cumulative_rewards[index - 1] + reward

            algo.update(chosen_arm, reward)
        result.append(cumulative_rewards)

    # 多次模拟求平均
    average = np.sum(np.array(result), axis=0) / num_sims

    return list(average)


def draw_average_reward(arms, num_sims=5000, times=250):

    algo = UCB1([], [])
    algo.initialize(len(arms))
    cumulative_rewards = get_cumulative_reward(algo, arms, num_sims, times)

    average = list(
        map(lambda x: x / (cumulative_rewards.index(x) + 1),
            cumulative_rewards))


    plt.plot(average, label='UCB1')


    plt.legend()
    plt.xlabel('Time')
    plt.ylabel('Average Reward')
    plt.title('Performance of the UCB1 Algorithm')
    plt.show()


def draw_cumulative_reward(arms, num_sims=5000, times=250):

    algo = UCB1([], [])
    algo.initialize(len(arms))
    cumulative_rewards = get_cumulative_reward(algo, arms, num_sims, times)
    plt.plot(cumulative_rewards, label='UCB1')


    plt.legend()
    plt.xlabel('Time')
    plt.ylabel('Cumulative Reward')
    plt.title('Performance of the UCB1 Algorithm')
    plt.show()

means = [0.1, 0.1, 0.1, 0.1, 0.9]
random.shuffle(means)
arms = list(map(lambda mu: BernoulliArm(mu), means))

draw_average_reward(arms)

在这里插入图片描述
可以看到,一开始存在振荡,后来逐渐平稳。噪声的存在是因为UCB对于一些臂了解太少,从而产生倒退,随着实验的进行,这种倒退会越来越少。

draw_cumulative_reward(arms)

在这里插入图片描述

四、不同bandit算法的比较

接下来让我们使用epsilon-Greedy算法和Softmax算法的退火版本与UCB1算法进行对比,这省去了对参数的调整。

由下面的对比图,我们可以发现:

  • UCB1的行为要更为的嘈杂

  • epsilon-Greedy算法的表现不如Softmax算法。

  • UCB1所做的后退导致它在大多数指标上的表现逊于Softmax算法,在其他环境下UCB1也许会表现得比Softmax好。

image-20230106131837364 image-20230106132124989

五、UCB算法的进一步探索

5.1 不同臂的奖励概率近似时

means2 = [0.1, 0.1, 0.1, 0.1, 0.12]
random.shuffle(means2)
arms2 = list(map(lambda mu:BernoulliArm(mu), means2))
draw_average_reward(arms2)

在这里插入图片描述

draw_cumulative_reward(arms2)

在这里插入图片描述

5.2 改变臂的数量

arms = []
nums = [5, 20, 50, 200]

# 随机生成数据
for num in nums:
    temp = [0.0 for col in range(num)]
    for i in range(num):
        temp[i] = random.random()
    means = list(map(lambda mu: BernoulliArm(mu), temp))
    arms.append(means)

result = []

for ar in arms:
    algo = UCB1( [], [])
    algo.initialize(len(ar))
    cumulative_rewards = get_cumulative_reward(algo, ar, 5000, 250)

    result.append(cumulative_rewards)

i = 0
for res in result:
    plt.plot(res, label='arms = {0}'.format(nums[i]))
    i += 1

plt.legend()
plt.xlabel('Time')
plt.ylabel('Cumulative Reward')
plt.title('Performance of the Epsilon Greedy Algorithm')
plt.show()

在这里插入图片描述

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

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

相关文章

Springboot 接口为null的值不返回对应的key

偶然听到两个应届生一段对话,一个后端,一个前端 。 前端: 大哥,你没有值就不要返回那个key行不行? 后端: 什么我看看。 后端: 这是本来返回值实体有的,不是必填,所以n…

Lua 元表及常见元方法

一、什么是元表 Lua 中的 table 使用起来有点像c中的 map 或者 unordered_map ,都是通过对应的key 获取对应的value。如果访问了表中不存在的key时,就会触发Lua的一种机制,Lua也正是凭借这个机制可以用来模拟类似“继承”的行为,…

低代码能够为企业带来什么?

目录 1、为企业快速开发应用赋能 2、低成本使用数字化工具 3、满足企业定制化需求 大数据时代的快速发展下,传统的应用开发技术手段渐渐地无法满足企业的高需求。并且,企业想在应用开发的基础上同时实现个性化定制,而传统的技术条件所需要…

Linux 进程概念(一)

目录 一、冯诺伊曼体系结构 二、操作系统(Operator System) 2.1 操作系统如何管理硬件? 2.2 操作系统如何管理软件? 2.3 一张图带你直观了解OS管理过程 三、进程(启示录) 3.1 进程的基本概念 3.1.1 进程PCB 3…

寒假本科创新——机器学习(二)

绪论1.3归纳偏好 一般原则:奥卡姆剃刀 什么样的算法比较好?1.4NFL定理 NFL定理的前提: NFL定理的寓意:1.3归纳偏好 归纳偏好(lnductive Bias): 机器学习算法在学习过程中对某种类型假设的偏好…

sql语句练习2

1、列出至少有一个员工的所有部门编号、名称,并统计出这些部门的平均工资、最低工资、最高工资 做法: 第一步:找出至少有一个员工的部门编号mysql>select deptno,count(empno)from empgroup by deptnohaving count(empno)>0; 第二步: …

node.js快速入门指南

Node.js迅速蹿红,衍生了一个强大的开源社区、支持企业,甚至还拥有属于自己的技术大会。我把这种成功归结于它的简介,高校,同时提高了编程生产力。 Node.js 的前置知识很多,例如以下知识 JavaScriptES6Ajax 还不会的…

Java JVM:虚拟机性能监控、故障处理工具(三)

目录标题一、基础故障处理工具二、可视化故障处理工具三、其他故障相关一、基础故障处理工具 JMC(Java Mission Control)以及JFR(Java Flight Recorder) JMC 从 Java7 以后包含在 JDK 中,直接输入 jmc 就能启动在使用…

JEECGboot数据规则篇

使用 一、功能说明 列表数据权限,主要通过数据权限控制行数据,让不同的人有不同的查看数据规则; 比如: 销售人员只能看自己的数据;销售经理可以看所有下级销售人员的数据;财务只看金额大于5000的数据等等…

js事件高级

文章目录一、注册事件(绑定事件)1、注册事件概述(1)传统注册方式(2)方法监听注册方式2、addEventListener 事件监听方式3、attachEvent 事件监听方式4、注册事件兼容性解决方案二、删除事件(解绑…

C库函数:string.h

string.h C 标准库 – <string.h> | 菜鸟教程 (runoob.com) 1void *memchr(const void *str, int c, size_t n) 在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c&#xff08;一个无符号字符&#xff09;的位置。在这个函数中&#xff0c;可以看到有void …

使用docker安装zabbix监控

官网手册&#xff1a;docker安装zabbix 首先需要安装好docker服务 创建专用于Zabbix组件容器的网络 docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 zabbix-net启动空的 MySQL 服务器实例 docker run --name mysql-server -t \ //mysql容器…

FFMPEG完美入门资料---002---FFmpeg 支持能力说明

FFMPEG入门资料---001---介绍和参数说明_音视频开发老马的博客-CSDN博客 接着上文写&#xff1a; 2.3.1 FFmpeg 对编码解码器的支持 ffmpeg 支持的编解码器种类共有 280 多种&#xff0c; 涵盖了几乎所有常见音视频编码格式&#xff0c; 能解码几乎所有的音视频&#xff0c; …

月交付破万,长安深蓝成造车新势力“头部玩家”

近日&#xff0c;造车新势力纷纷公布2022年12月交付数据。通过数据&#xff0c;我们发现众多造车新势力都取得了不错的成绩&#xff0c;“头部玩家”的门槛甚至提升至万辆。与此同时&#xff0c;“排位”形势也与往年大相径庭&#xff0c;其中最令人意外的是2022年发布的深蓝品…

ESP8266+MicroPython开发:使用ESP8266+Thonny烧录MicroPython固件

使用ESP8266Thonny烧录MicroPython固件下载固件下载安装Thonny在Thonny烧录固件测试Thonny简单使用下载固件 MicroPython下载网址 根据ESP8266的flash选择&#xff0c;一般选择如图所示 自己随便选择一个版本下载&#xff0c;注意记住自己的下载路径 下载安装Thonny Thonn…

【vue系列-05】vue的生命周期(详解)

深入理解vue的生命周期一&#xff0c;vue的生命周期1&#xff0c;创建流程1.1&#xff0c;beforeCreate1.2&#xff0c;created2&#xff0c;挂载流程2.1&#xff0c;beforeMount2.2&#xff0c;mounted3&#xff0c;更新流程3.1&#xff0c;beforeUpdate3.2&#xff0c;update…

ConvNeXt V2论文翻译:ConvNeXt V2与MAE激情碰撞

文章目录摘要1 简介2 相关工作3 全卷积掩码自编码器4 全局响应归一化5 ImageNet实验6 迁移学习实验7 结论摘要 论文链接&#xff1a;ConvNeXt V2 在改进的架构和更好的表示学习框架的推动下&#xff0c;视觉识别领域在21世纪20年代初实现了快速现代化和性能提升。例如&#xf…

评价类模型(层次分析法与模糊评价模型)

一、评价类模型 综合评价的基本理论和数据预处理&#xff1a; 评价对象评价指标权重系数综合评价模型评价者 二、AHP法—层次分析法 通过打分解决评价类问题&#xff0c;两两比较&#xff0c;推算权重。 %function RIAHPRI(n) %利用MATLAB求随机一致性指标; i0;CI0;Azer…

pyqt5下的QInputDialog跟QFileDialog以及关闭主窗口子窗口自动关闭

QInputDialog 具体的参数可以参考&#xff1a; Qt&#xff1a;30---QInputDialog标准输入对话框_mb6128aabee41d4的技术博客_51CTO博客 官网连接&#xff1a; QInputDialog Class | Qt Widgets 5.15.12 这里只介绍QInputDialog.getText 代码实现&#xff1a; from PyQt5.…

【从零开始学爬虫】采集食品行业最新报价数据

l 采集网站 【场景描述】采集食品行业最新报价数据。 【源网站介绍】中国报告大厅网休闲食品行业数据频道提供休闲食品行业数据信息&#xff0c;在此有大量休闲食品行业数据信息可供选择&#xff0c;是一个可以帮助休闲食品行业了解数据的平台。 【使用工具】前嗅ForeSpider…