强化学习编程实战-1-一个及其简单的强化学习实例(多臂赌博机)

1.1 多臂赌博机

        一台拥有K个臂的机器,玩家每次可以摇动K个臂中的一个,摇动后,会吐出数量不等的金币,吐出金币的数量服从一定的概率分布,而且不同臂的概率分布不同。

        多臂赌博机的问题是:假设玩家共有N次摇地摇臂的机会,每次如何选择摇动才能使N轮之后得到的金币最多?

        对于这个问题,如果提前知道哪个臂吐的金币最多,那么可以每次都摇动那个臂。但是,问题使并不知道那个臂能获得最多金币?该采取什么策略?

 

1.1.1 eq?%5Cvarepsilon-greedy策略

        一个很直观的想法:既然不知道哪个臂吐的金币最多,那么可以先对每个臂都尝试几次(如都10次),找出那个臂吐出的金币最多,然后一直摇动它。

        其实这个最简单、最朴素的想法已经蕴含了算法学习最基本的两个过程:采集数据和学习。首先,对每个臂进行尝试就是采集数据,其次,学习就是利用这些数据知道哪个臂回吐出最多的金币。一个最简单的方法就是计算每个臂的平均吐钱数量,然后,一直摇那个臂。

        我们可以将这个算法用形式化的代数来表示。用s表示当前赌博机,用A表示可以选择的动作,即A={1,2,3}。其中a=1表示摇动第一个臂,依次类推。用回报eq?%5Cgamma表示摇动赌博机的摇臂后获得的金币的数目。用Q(a)表示摇动动作a获得的金币的平均回报,则eq?Q%28a%29%3D%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%5Cgamma%20_%7Bi%7D,其中n为摇动动作的总次数。R(a)为摇动动作a的总回报。

        算法的伪代码

00b3aa0e16254d5eb84a42592496d306.png

1-3行:初始化每个动作的总回报R(a),以及摇动该动作的次数N(a)。

4-6行:每个臂都尝试eq?n_%7Ba%7D次,计算每个摇臂总的金币数。

7-9行:算出使得总回报最大的那个臂,然后一直摇动它。

这是一个简单、朴素的想法,但并不是一个好的算法。原因如下:缺点
(1)不应该以总回报最大为目的来选择当前哪个臂,而是应该选择当前平均回报最大的臂

(2)不应该只摇动当前平均回报最大的臂,因为它不一定使最好的那个臂。所以,我们除了关注当前平均回报最大的臂,还要保留一定的概率去摇动其他的臂,以便发现更好的臂。

以上两点对应着强化学习算法中最重要的概念:利用策略和探索策略平衡。

利用:exploitation,是利用当前的数据总结得到的最好的策略,采用该策略,我们可以得到较高的回报。

探索:exploration,该策略可以帮我们找到更好的臂,甚至找到最优的臂。

        强化学习算法在训练的过程中所用到的策略是平衡了利用和探索的策略,最常见的是eq?%5Cvarepsilon-greedy策略,公式表示:

0d853fb12db340eba68275ffa943a53f.png

        该策略,在每次选择摇动哪个臂时,应该以1-eq?%5Cvarepsilon的概率去摇动当前平均值最大的臂,以eq?%5Cvarepsilon的概率在所有动作中均匀随机地选择动作。这样可以在有限的次数中得到尽可能多的回报,同时不失去找到最好的臂的机会。

1d5a821d6895478c9aa3d02b25bef4a2.png

第1-4行:初始化总回报R(a),初始化每个动作的平均回报Q(a),每个动作的次数N(a).

第6行:在每次摇臂之前,采用eq?%5Cvarepsilon-greedy策略,选择要摇动的臂a。

第7行:动作a的次数N(a)+1.

第8行:根据动作a和环境返回的回报eq?%5Cgamma_%7B%7D(a),更新动作a的平均回报。

第9行:计算总的收益。

第10行:玩家尝试N次之后,返回总的收益。

在多臂赌博机中,平衡利用和探索的策略还有玻尔兹曼策略和UCB策略。

 

1.1.2 玻尔兹曼策略

        e-greedy策略给对应值函数最大的那个动作一个比较大的概率,而其他动作,不管值函数的大小如何,被采样的概率都是相等。

        但这中概率的分配策略不太合理。按理说,非贪婪的动作也有好坏之分,那些对应值函数大的动作应该比那些对应值函数小的动作采样的概率大。于是玻尔兹曼策略根据值函数对动作的采样的概率进行了软处理,表示下式1-2为

d60a9ffda8cf42cbb36781d92faeb299.png

其中eq?%5Ctau为温度调节参数,可以用来调节探索和利用和比例。eq?%5Ctaueq?%5Ctau越小,玻尔兹曼越接近贪婪策略,利用所占的比例越大,探索越少。反之,探索越多。伪代码只需替换图1-3中的e-greedy策略为公式1-2.

 

1.1.3 UCB策略

UCB(Upper Confidence Boundn)置信上限。在统计学中常常用置信区间来表示不确定性。在这里,我们用置信区间来表示探索。

UCB策略公式

4edfe00e78e8460b9e819fbd557c3fd3.png

其中t为当前摇臂动作的总次数,N(a)为动作a的总次数。

下图为3种策略,总回报和摇动次数之后的关系。e-greedy策略回报最低,但却是形式最简单、最通用,可广泛用于各种任务的学习和探索训练中。

74bc4083f35b46ab9a875f9c7654e892.png

 

1.2 多臂赌博机代码实现

基于上文提到的三种学习策略。

①首先,我们先创建一个KB_Game类

②在类KB_Game中定义方法step(),用于模拟多臂赌博机如何给出回报。该方法的输入为动作,输出为回报。用正态分布来模拟玩家在每次摇动摇臂后得到的回报。step()方法实际上提供了多臂赌博机的模拟器。

③接下来,实现3种选择动作的策略方法choose_action().该方法的输入参数为测量类别policy,有3种,对应上文的三种策略e_greedy,ucb和boltzmann.另外还有一个参数字典**kwargs,对应传递相应的策略的所对应超参数,如e-greedy策略中的epsilon,UCB策略中的超参数c_ratio,以及玻尔兹曼中的温度‘temperature'.UCB算法的每一步是依次摇动每个臂,因此在程序中对应的代码为判断每个动作的次数,如果有等于零的,那么选择该动作。

④有了模拟器和动作选择策略,下面就可以通过交互进行学习训练。定义方法train().该方法的输入参数有play_total(表示训练的总次数),policy(训练的策略),**kwargs(相应策略的超参数字典).

⑤智能体通过学习的策略选择动作,然后将动作传给step()方法,相当于跟多臂赌博机进行了一次交互,从多臂赌博机中获得回报r,智能体根据立即回报更新每个动作的平均回报q,计算当前的累计回报并作相应的保存。

⑥在每次训练新的策略的时候,我们需要将类KB_Game中的成员变量进行重置,定义reset()方法进行重置,重置的变量有平均回报q,各动作的次数action_counts,当前的累积回报current_cumulative_reward,玩家尝试的次数counts,玩家尝试的历史counts_history、玩家累积回报的历史cumulative_rewards_history、动作a、回报reward。

 ⑦为了更直观比较3种不同策略的学习性能,需要画图展示,我们用方法plot()来实现。得到如下的结果。显然ucb比其他两个策略要好。

23a19cf0d2894248855a1a19c7c2c415.png

代码如下

import numpy as np
import matplotlib.pyplot as plt
class KB_Game:def __init__(self,*args,**kwargs):self.q=np.array([0.0,0.0,0.0])          #每个臂的平均回报self.action_counts=np.array([0,0,0])    #摇动每个臂的次数self.current_cumulative_rewards=0.0     #当前累积回报总和self.actions=[1,2,3]                    #3个不同的摇臂self.counts=0                           #玩家玩游戏的次数self.counts_history=[]                  #玩家而玩游戏的次数记录self.cumulative_rewards_history=[] #累积回报的记录self.a=1                  #玩家当前动作,初始化为1,摇第一个摇臂self.reward=0             #当前回报,初始值为0def step(self,a):#模拟器r=0if a==1:r=np.random.normal(1,1)     #正态分布,均值为1,方差为1if a==2:r=np.random.normal(2,1)if a==3:r=np.random.normal(1.5,1)return rdef choose_action(self,policy,**kwargs):  #动作策略action=0if policy=='e_greedy':if np.random.random()<kwargs['epsilon']:action=np.random.randint(1,4)else:action=np.argmax(self.q)+1if policy=='ucb':c_ratio=kwargs['c_ratio']if 0 in self.action_counts:action=np.where(self.action_counts==0)[0][0]+1else:value=self.q+c_ratio*np.sqrt(np.log(self.counts)/self.action_counts)action=np.argmax(value)+1if policy=='boltzmann':tau=kwargs['temperature']p=np.exp(self.q/tau)/(np.sum(np.exp(self.q/tau)))action=np.random.choice([1,2,3],p=p.ravel())return actiondef train(self,play_total,policy,**kwargs):reward_1=[]reward_2=[]reward_3=[]for i in range(play_total):action=0if policy=='e_greedy':action=self.choose_action(policy,epsilon=kwargs['epsilon'])if policy=='ucb':action=self.choose_action(policy,c_ratio=kwargs['c_ratio'])if policy=='boltzmann':action=self.choose_action(policy,temperature=kwargs['temperature'])self.a=action#print(self.a)#与环境交互一次self.r=self.step(self.a)self.counts+=1#更新值函数self.q[self.a-1]=(self.q[self.a-1]*self.action_counts[self.a-1]+self.r)/(self.action_counts[self.a-1]+1)self.action_counts[self.a-1]+=1reward_1.append([self.q[0]])reward_2.append([self.q[1]])reward_3.append([self.q[2]])self.current_cumulative_rewards+=self.rself.cumulative_rewards_history.append(self.current_cumulative_rewards)self.counts_history.append(i)def reset(self):self.q=np.array([0.0,0.0,0.0])          #每个臂的平均回报self.action_counts=np.array([0,0,0])    #摇动每个臂的次数self.current_cumulative_rewards=0.0     #当前累积回报总和self.counts=0                           #玩家玩游戏的次数self.counts_history=[]                  #玩家而玩游戏的次数记录self.cumulative_rewards_history=[] #累积回报的记录self.a=1                  #玩家当前动作,初始化为1,摇第一个摇臂self.reward=0             #当前回报,初始值为0def plot(self,colors,policy,style):plt.figure(1)       #创建画布plt.plot(self.counts_history,self.cumulative_rewards_history,colors,label=policy)plt.legend() #加上图列plt.xlabel('n',fontsize=18)plt.ylabel('total rewards',fontsize=18)if __name__=='__main__':np.random.seed(0)k_gamble=KB_Game()total=2000k_gamble.train(play_total=total,policy='e_greedy',epsilon=0.05)k_gamble.plot(colors='r',policy='e_greedy',style='-.')k_gamble.reset()k_gamble.train(play_total=total,policy='boltzmann',temperature=1)k_gamble.plot(colors='b',policy='boltzmann',style='--')k_gamble.reset()k_gamble.train(play_total=total,policy='ucb',c_ratio=0.5)k_gamble.plot(colors='g',policy='ucb',style='-')plt.show()

 

 

 

 

 

 

 

 

 

        

 

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

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

相关文章

WPF中Background=“{x:Null}“ 和 Transparent

WPF中关于背景透明和背景无 此时&#xff0c;我代码中是写的有有个控件&#xff0c;一个Border &#xff0c;一个TextBox &#xff0c;范围都是全屏这么大&#xff0c;可以输入TextBox 因为&#xff0c;当border没有设置背景的时候&#xff0c;实际上是&#xff1a; <Borde…

尚庭公寓——数据库设计

1. 数据的关系 一对一&#xff0c;一对多&#xff08;多对一&#xff09;&#xff0c;多对多 2. 实体关系模型 实体关系模型常用ER图&#xff08;enity relationship graph&#xff09;表示&#xff1b; 矩形表示实体&#xff08;类似Java中的对象&#xff0c;如学生就是一…

NoSQL 之 Redis 配置与常用命令

一、关系型数据库与非关系型数据库 1、数据库概述 &#xff08;1&#xff09;关系型数据库 关系型数据库是一个结构化的数据库&#xff0c;创建在关系模型&#xff08;二维表格模型&#xff09;基础上&#xff0c;一般面向于记 录。 SQL 语句&#xff08;标准数据查询语言&am…

在5G/6G应用中实现高性能放大器的建模挑战

来源&#xff1a;Modelling Challenges for Enabling High Performance Amplifiers in 5G/6G Applications {第28届“集成电路和系统的混合设计”(Mixed Design of Integrated Circuits and Systems)国际会议论文集&#xff0c;2021年6月24日至26日&#xff0c;波兰洛迪} 本文讨…

Vue中Class数据绑定

Class数据绑定 数据绑定的一个常见需求场景是操作CSS class列表&#xff0c;因为class是attribute&#xff08;属性&#xff09;&#xff0c;我们可以和其他attribute一样使用v-bind 将它们和动态的字符串绑定。但是&#xff0c;在处理比较复杂的绑定时&#xff0c;通过拼接生…

金蝶云苍穹-插件开发(一)加载数据

前言 此系列博客是进行金蝶云苍穹开发时的插件开发的教程&#xff0c;一是在明年要是还要参加软件杯金蝶A6赛题的话&#xff0c;可以看此系列教程的博客来进行复习&#xff0c;同时如果要是我实验室的学弟学妹要参加的话&#xff0c;我这个系列的博客可以给他们提供学习参考&a…

谷粒商城学习-10-docker安装mysql

文章目录 一&#xff0c;拉取MySQL镜像1&#xff0c;搜索MySQL的Docker镜像2&#xff0c;拉取MySQL镜像3&#xff0c;查看已经拉取的镜像 二&#xff0c;创建、启动MySQL容器1&#xff0c;使用docker run创建启动容器2&#xff0c;使用docker ps查看运行状态的容器3&#xff0c…

SpringBoot新手快速入门系列教程:基于JPA的一个Mysql简单读写例子

现在我们来做一个简单的读写Mysql的项目 1&#xff0c;先新建一个项目&#xff0c;我们叫它“HelloJPA”并且添加依赖 2&#xff0c;引入以下依赖&#xff1a; Spring Boot DevTools (可选&#xff0c;但推荐&#xff0c;用于开发时热部署)Lombok&#xff08;可选&#xff0c…

【C++】 解决 C++ 语言报错:Use of Uninitialized Variable

文章目录 引言 使用未初始化的变量&#xff08;Use of Uninitialized Variable&#xff09;是 C 编程中常见且危险的错误之一。它通常在程序试图使用尚未赋值的变量时发生&#xff0c;导致程序行为不可预测&#xff0c;可能引发运行时错误、数据损坏&#xff0c;甚至安全漏洞。…

SpringMVC:SpringMVC执行流程

文章目录 一、介绍二、什么是MVC 一、介绍 Spring MVC 是一种基于Java的Web框架&#xff0c;它采用了MVC&#xff08;Model - View - Controller&#xff09;设计模式&#xff0c;通过吧Model、View和Controller分离&#xff0c;将Web层进行职责解耦&#xff0c;把复杂的Web应…

NAS 必备导航页 Homepage 外观简约但功能丰富

本文首发于只抄博客,欢迎点击原文链接了解更多内容。 前言 NAS 上的应用部署多了之后,不同的服务对应的端口很难记住,在内网中使用,一般也不会绑定域名。 此时就需要有一个导航页将 NAS 上部署的所有服务都罗列出来,方便我们直接点击访问对应的服务。 今天给大家介绍的…

【HICE】转发服务器实验

1.在本地主机上操作 2.在客户端操作设置主机的IP地址为dns 3.测试,客户机是否能ping通

anaconda中下载压缩包并用conda安装包

有时直接conda安装包时会出错&#xff1b;报错PackagesNotFoundError: The following packages are not available from current channels 比如 conda install -y bioconda::ucsc-gtftogenepred #直接安装报错 #直接下载压缩包安装https://blog.csdn.net/weixin_45552562/ar…

C++初学者指南-4.诊断---基础:警告和测试

C初学者指南-4.诊断—基础知识&#xff1a;警告和测试 文章目录 C初学者指南-4.诊断---基础知识&#xff1a;警告和测试1. 术语和技术记住&#xff1a;使用专用类型&#xff01; 2.编译器警告Gcc/CLang 编译器选项MS Visual Studio 编译器选项 3.断言运行时断言静态断言&#x…

macOS查看系统日志的方法

1、command空格键打开搜索框&#xff0c;输入‘控制台’并打开 2、选择日志报告&#xff0c;根据日期打开自己需要的文件就可以

c++习题06-ljc的储蓄计划

目录 一&#xff0c;问题 二&#xff0c;思路 1&#xff0c;思路1 2&#xff0c;思路2 三&#xff0c;代码 1&#xff0c;思路1代码 2&#xff0c;思路2代码 四&#xff0c;用例输入输出 一&#xff0c;问题 二&#xff0c;思路 1&#xff0c;思路1 定义变量&#x…

统计是一门艺术(非参数假设检验)

1.定义 当总体分布未知&#xff0c;那么就需要一种与分布具体数学形式无关的统计推断方法&#xff0c;称为非参数方法 只能利用样本中的一般信息包括位置和次序关系等 稳健性强 2.符号检验 考虑问题&#xff1a; 小样本情况&#xff1a; 以概率为1/2的二项分布是对称的 两…

剖析DeFi交易产品之UniswapV3:交易路由合约

本文首发于公众号&#xff1a;Keegan小钢 SwapRouter 合约封装了面向用户的交易接口&#xff0c;但不再像 UniswapV2Router 一样根据不同交易场景拆分为了那么多函数&#xff0c;UniswapV3 的 SwapRouter 核心就只有 4 个交易函数&#xff1a; exactInputSingle&#xff1a;指…

Java技术栈总结:kafka篇

一、# 基础知识 1、安装 部署一台ZooKeeper服务器&#xff1b;安装jdk&#xff1b;下载kafka安装包&#xff1b;上传安装包到kafka服务器上&#xff1a;/usr/local/kafka;解压缩压缩包&#xff1b;进入到config目录&#xff0c;修改server.properties配置信息&#xff1a; #…

Buuctf之SimpleRev做法

首先&#xff0c;查个壳&#xff0c;64bit&#xff0c;那就丢进ida64中进行反编译进来之后&#xff0c;我们进入main函数&#xff0c;发现里面没什么东西&#xff0c;那就shiftf12搜索字符串&#xff0c;找到关键字符串&#xff0c;双击进入然后再选中该字符串&#xff0c;ctrl…