强化学习代码分析之多臂赌博机

前言

主要参考的是《Reinforcement Learning: An introduction Second Edition》这本书里的例子
英文版地址:http://incompleteideas.net/book/first/ebook/the-book.html
代码源文件可以参考这篇回答:https://zhuanlan.zhihu.com/p/79701922 采用Matlab实现

问题描述

本章节代码主要用来评估 \(greedy\) 策略和 \(\varepsilon -greedy\) 策略的有效性
问题设定:每个赌博机问题设置10个摇臂,进行一轮(1000次)选择,独立重复2000轮,对学习算法表现进行评估。
问题假设:每个问题的动作真实价值服从均值为0方差为1的标准正态分布;选择的动作的奖励由一个均值为动作真实价值,方差为1的正态分布决定。

代码实现

代码思路:
强化学习代码的一般思路是初始化指标、状态、动作、奖励等,环境已知则构建环境;模拟学习过程开始交互,交互过程中对互动结果进行记录,当然还包含各种值函数等的更新;总结展示结果。
在该问题中主要思路及步骤如下:

  1. 初始化动作的真实价值(均值为0,标准差为1的正态分布随机数)、游戏参数(赌博机个数、摇臂个数、每个赌博机玩的次数、\(\varepsilon -greedy\)中的\(\varepsilon\)
  2. 为指标做准备(每次的最优动作是什么,选择的是不是最优的 为计算选择最优动作百分比做准备;reward为绘制每个动作的平均回报做准备)【就是构造空向量来存储结果】
  3. 游戏开始:轮次循环,每轮选择循环,依据策略选择动作,查看选择的动作是不是最优动作为指标计算做准备(先全部都随机初始化为0,所有值相同时随机选择,然后依据上帝视角为其产生真值。根据结果更新指标一次,为绘图做准备)【比较不同策略只需要在选择方式上进行改变即可】
    · 在这个问题中 动作值的更新方式是采用采样平均法记录了每次选择这个动作的reward来取均值进行计算,可以采用增量式实现。这样每次只需要记录三个数字,节约资源,加快了运算速度。

代码内容:

% 设置游戏参数
nB = 2000;  
nA = 10; 
nP = 1000; 
sigma = 1.0; 

% generate the TRUE reward Q^{\star}: 
qStarMeans = mvnrnd( zeros(nB,nA), eye(nA) ); 
%生成真实动作值q*,每个赌博机各动作的q*服从均值为0,方差1的正态分布                                            
%函数mvnrnd生成多维正态分布数据                                             
%qStarMeans大小是2000x10,每一行都服从均值0,方差为1的正态分布
% run an experiment for each epsilon:
epsArray = [ 0, 0.01, 0.1 ]; %, 1 ];  % epsilon数组
%要比较的性能指标
avgReward    = zeros(length(epsArray),nP);  %平均reward
perOptAction = zeros(length(epsArray),nP);  %选择最优动作的百分比
% cumReward    = zeros(length(epsArray),nP);  %累计reward
% cumProb      = zeros(length(epsArray),nP);  %累计选择最优动作的百分比
tic
for ei=1:length(epsArray), 
  tEps = epsArray(ei); 
%%参数初始化
qT = zeros(size(qStarMeans)); % <- initialize to zero draws per arm (no knowledge) 每个摇臂的q值初始化为0,数组大小2000*10
qN = ones( nB, nA ); % keep track of the number draws on this arm %记录每个摇臂被选择的次数
qS = qT;             % keep track of the SUM of the rewards (qT = qS./qN) %记录每个摇臂的总的reward,                      
allRewards  = zeros(nB,nP); %记录每个赌博机每次pull得到的reward
pickedMaxAction = zeros(nB,nP); %记录每个赌博机每次pull选取的动作是否为最大q值对应的动作
%%进行游戏
for bi=1:nB, % pick a bandit 进行nB次赌博机任务
   for pi=1:nP, % make a play 每次任务摇nP次
      % determine if this move is exploritory or greedy: e-greedy
      % 策略,每次动作要么是探索性的,要么是greedy的
      if( rand(1) <= tEps ) % pick a RANDOM arm: 
        [dum,arm] = histc(rand(1),linspace(0,1+eps,nA+1)); clear dum; %histc函数中rand(1),产生一个随机数
                                                                      %linspace(0,1+eps,nA+1)产生一个维数为nA+1的[0,1+eps]间的等差数列
                                                                      %观察产生的随机数属于哪个左闭右开的子区间
                                                                      %输出:dum:落在某个区间的值的数量;arm:属于第几个区间
      else                  % pick the GREEDY arm:
        [dum,arm] = max( qT(bi,:) ); clear dum; 
      end
      % determine if the arm selected is the best possible: 确定选择的摇臂是否为最好的
      [dum,bestArm] = max( qStarMeans(bi,:) ); 
      if( arm==bestArm ) pickedMaxAction(bi,pi) = 1; end
      % get the reward from drawing on that arm: 
      reward = qStarMeans(bi,arm) + sigma*randn(1); %每个摇臂每次被选择后得到的reward服从正太分布,均值为q*,方差为1
      allRewards(bi,pi) = reward; 
      % update qN,qS,qT: 
      qN(bi,arm) = qN(bi,arm)+1;%更新每个摇臂被选择的次数
      qS(bi,arm) = qS(bi,arm)+reward; %更新每个摇臂的总的reward,
      qT(bi,arm) = qS(bi,arm)/qN(bi,arm); %更新动作值的估计值
    end
  end

总结

在这个基代码中,所有动作的价值初始化为0。如果实施一个动作后其价值为正,那么采用贪婪策略进行动作选择时会一直采取这个动作,不会继续探索其余的动作。所以当使用单纯的贪婪策略时,应当结合乐观初始值方法一起食用,效果更佳。
在该问题中,动作价值的估计采用求和平均法。一种是记录所有求平均,一种是增量式实现,只是计算方法不同。

文中提到的这两种策略各有利弊,实际效果与具体任务也有关系:
奖励的方差(方差大,需要多探索;方差小,贪婪策略即可)
\(\varepsilon -greedy\) 策略探索尺度的控制(置信上下区间等)

posted @ 2021-05-31 10:59  芋圆院长  阅读(131)  评论(0编辑  收藏  举报