强化学习笔记:多臂老虎机问题(6)--Upper Confidence Bound

目录

0. 前言

1. 算法原理

2. Python仿真

2.1 k_armed_bandit_one_run()改造

2.2  仿真对比Epsilon-greedy方法和UCB方法

3. 习题


0. 前言


        前面几节我们已经就多臂老虎机问题进行了一些讨论。详细参见本系列总目录:

        强化学习笔记总目录

        本节我们继续基于基于多臂老虎机问题的不同epsilon-greedy的另一种行动选择方法:Upper Confidence Bound action selection

        Ref: Sutton-RLBook2020-2.7: Upper-Confidence-Bound Action Selection

1. 算法原理

        在强化学习中,探索的必要性是因为对于行动价值的估计始终都存在不确定性。贪婪行动(greedy actions)是指基于到目前为止的估计结果看上去最优的行动,但是其它行动有可能更好(只不过探索得不够尚未发现而已)。Epsilon-greedy行动选择机制强制性地以一定概率选择greedy actions以外的行动,但是以无差别的方式进行。事实上对于非贪婪行动,根据到目前为止的探索结果,成为最优行动的可能性(或者潜力)也是不一样的,分为几种情况:

  1. 第一种是行动价值估计值虽然不是当前最优但是比较接近最优,因此比较有希望称为新的最优,这种行动应该在探索中给予更多的机会
  2. 第二种是被探索的次数很少,因此它的不确定性很大,因此也应该在探索中给予更多的机会
  3. 第三种是探索的次数很充分但是行动价值估计值不乐观,因此成为最优的可能性比较低,这种行动应该在探索中所给予的机会可以降低

        对于Epsilon-greedy行动选择机制的一种可能的改进方案是,在探索中给那些有更大潜力或者希望称为最优的飞贪婪行动更多的机会,兼顾两方面的因素:(a)当前的行动价值估计值;(b)不确定性—主要由已经被选择的次数来衡量.

        以下为一种实施这一策略的有效的行动选择方式:

        针对每一个行动a维护一个评估量 ,其中各项的物理含义分别说明如下:

  1. : 到当前到目前时刻t为止的行动价值估计值,代表成为最优行动的可能性的现实部分
  2. c表示加权系数,用于控制倾向于探索的程度(degree of exploration)
  3. 统计到目前时刻t为止行动a被选择的次数。 代表行动a的不确定性,或者说行动a的价值估计的方差,或者可以说是置信度(的倒数)。如果一个行动被选择次数越多意味着它的行动价值估计的确定性就越小(即成反比关系),因此 出现在分母。比如说,如果某个行动被选择次数还是0的话,那就意味着该行动在exploring中应该以最高优先度被选择

2. Python仿真

2.1 k_armed_bandit_one_run()改造

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

         基于上一篇中的k_armed_bandit_one_run()进行以下两点的改造:

        (1) 追加一个参数actsel用于指定行动选择算法,缺省设置为None时表示epsilon-greedy
        (2) 在采用UCB算法时,epsilon参数用作UCB算法中的控制参数c

def k_armed_bandit_one_run(qstar,epsilon,nStep,Qinit,QUpdtAlgo='sample_average',alpha=0, stationary=True, actsel=None):
    """
    One run of K-armed bandit simulation.
    Add Qinit to the interface.
    Input:
        qstar:     Mean reward for each candition actions
        epsilon:   Epsilon value for epsilon-greedy algorithm
        nStep:     The number of steps for simulation
        Qinit:     Initial setting for action-value estimate
        QUpdtAlgo: The algorithm for updating Q value--'sample_average','exp_decaying'
        alpha:     step-size in case of 'exp_decaying'
        actsel:    Specifying action selection algorithm
    Output:
        a[t]: action series for each step in one run
        r[t]: reward series for each step in one run
        Q[k]: reward sample average up to t-1 for action[k]
        aNum[k]: The number of being selected for action[k]
        optRatio[t]: Ration of optimal action being selected over tim
    """
    
    #print('QUpdtAlgo=',QUpdtAlgo)
    #print('Qinit=',Qinit)
    #print('actsel=',actsel)
    #print('qstar=',qstar)
    #print('epsilon=',epsilon)
            
    K     = len(qstar)
    Q     = Qinit
    a     = np.zeros(nStep+1,dtype='int') # Item#0 for initialization
    aNum  = np.zeros(K,dtype='int')       # Record the number of action#k being selected
    
    r     = np.zeros(nStep+1)             # Item#0 for initialization

    if stationary == False:
        qstar = np.ones(K)/K                 # qstart initialized to 1/K for all K actions    
    
    optCnt   = 0
    optRatio = np.zeros(nStep+1,dtype='float') # Item#0 for initialization

    for t in range(1,nStep+1):

        #0. For non-stationary environment, optAct also changes over time.Hence, move to inside the loop.
        optAct   = np.argmax(qstar)
                
        #1. action selection
        if actsel == 'UCB':
            aMax = -np.Inf            
            for k in range(K):
                if aNum[k] == 0:
                    aMetric = np.inf
                else:
                    aMetric = Q[k] + epsilon * np.sqrt(np.log(t)/aNum[k])
                if aMax < aMetric:
                    aOpt = k
                    aMax = aMetric
            a[t] = aOpt                                
        else:
            tmp = np.random.uniform(0,1)
            if tmp < epsilon: # random selection
                a[t] = np.random.choice(np.arange(K))
                #print('random selection: a[{0}] = {1}'.format(t,a[t]))
            else:             # greedy selection
                #选择Q值最大的那个,当多个Q值并列第一时,从中任选一个--但是如何判断有多个并列第一的呢?
                #对Q进行random permutation处理后再找最大值可以等价地解决这个问题
                p = np.random.permutation(K)
                a[t] = p[np.argmax(Q[p])]
                #print('greedy selection: a[{0}] = {1}'.format(t,a[t]))

        aNum[a[t]] = aNum[a[t]] + 1

        #2. reward: draw from the pre-defined probability distribution    
        r[t] = np.random.randn() + qstar[a[t]]        

        #3.Update Q of the selected action - #2.4 Incremental Implementation
        # Q[a[t]] = (Q[a[t]]*(aNum[a[t]]-1) + r[t])/aNum[a[t]]    
        if QUpdtAlgo == 'sample_average':
            Q[a[t]] = Q[a[t]] + (r[t]-Q[a[t]])/aNum[a[t]]    
        elif QUpdtAlgo == 'exp_decaying':
            Q[a[t]] = Q[a[t]] + (r[t]-Q[a[t]])*alpha
        
        #4. Optimal Action Ratio tracking
        #print(a[t], optAct)
        if a[t] == optAct:
            optCnt = optCnt + 1
        optRatio[t] = optCnt/t

        #5. Random walk of qstar simulating non-stationary environment
        # Take independent random walks (say by adding a normally distributed increment with mean 0
        # and standard deviation 0.01 to all the q⇤(a) on each step).   
        if stationary == False:        
            qstar = qstar + np.random.randn(K)*0.01 # Standard Deviation = 0.01
            #print('t={0}, qstar={1}, sum={2}'.format(t,qstar,np.sum(qstar)))
        
    return a,aNum,r,Q,optRatio

2.2  仿真对比Epsilon-greedy方法和UCB方法

(1) Action selction: epsilon-greedy with epsilon=0.1 vs UCB

(2) Q estimation method: sample-average method

(3) Environment: stationary

nStep = 1000
nRun  = 2000
K     = 10

r_1   = np.zeros((nRun,nStep+1))
r_2   = np.zeros((nRun,nStep+1))
optRatio_1 = np.zeros((nRun,nStep+1))
optRatio_2 = np.zeros((nRun,nStep+1))

for run in range(nRun):
    print('.',end='')
    if run%100==99:        
        print('run = ',run+1)
    
    qstar   = np.random.randn(10)     
    a,aNum,r_1[run,:],Q,optRatio_1[run,:] = k_armed_bandit_one_run(qstar,epsilon=0.1,nStep=nStep,Qinit=np.zeros(K),actsel=None)
    a,aNum,r_2[run,:],Q,optRatio_2[run,:] = k_armed_bandit_one_run(qstar,epsilon=2,nStep=nStep,Qinit=np.zeros(K),actsel='UCB')
rEnsembleMean_greedy = np.mean(r_1,axis=0)
rEnsembleMean_ucb = np.mean(r_2,axis=0)
#rEnsembleMean_ucb_c3 = np.mean(r_3,axis=0)

optRatioEnsembleMean_greedy = np.mean(optRatio_1,axis=0)
optRatioEnsembleMean_ucb = np.mean(optRatio_2,axis=0)
#optRatioEnsembleMean_ucb_c3 = np.mean(optRatio_3,axis=0)

fig,ax = plt.subplots(1,2,figsize=(15,5))

ax[0].plot(rEnsembleMean_greedy[1:])  # Note: t count from 1 in k_armed_bandit_one_run()
ax[0].plot(rEnsembleMean_ucb[1:])
#ax[0].plot(rEnsembleMean_ucb_c3[1:])
#ax[0].legend(['epsilon-greedy','UCB, c=2','UCB, c=3'])
ax[0].legend(['epsilon-greedy','UCB, c=2'])
ax[0].set_title('ensemble average reward')
ax[0].grid()

ax[1].plot(optRatioEnsembleMean_greedy[1:])
ax[1].plot(optRatioEnsembleMean_ucb[1:])
#ax[1].plot(optRatioEnsembleMean_ucb_c3[1:])
#ax[1].legend(['epsilon-greedy','UCB, c=2','UCB, c=3'])
ax[0].legend(['epsilon-greedy','UCB, c=2'])
ax[1].set_title('Optimal action selection ratio')
ax[1].grid()

         以上结果原原书结果基本吻合。

        如上图所示,UCB通常表现得更好,但是它的扩展性要比epsilon-greedy方法要差,即相比来说更难以推广应用到多臂老虎机以外的更通用的强化学习问题。其中一个困难在于非平稳环境的跟踪,在这种情况下,需要前面2.5节中所讨论的策略。另一个困难在于具有很大状态空间的问题的处理,尤其与如本书第2部分所讨论的那些需要使用函数近似的方法的场合(。。。呃不知所云。。。估计要学到后面回头再来看才能明白啥意思)。在这些更复杂的问题场景中,UCB方法通常变得不切实际。

3. 习题

解答:

        很显然这个”11-th step” 的spike与K=10是相关的。

        由于未被选择的行动的“融合度量”(即式(17)的评估值)为无穷大,所以在前10步中必然是轮流选择十个选项各一次。由于原始的qstar是标准正态分布的采样值,所以前10次的基于sample-average的奖励平均值基本上在0附近波动是符合预期的。第11步必然(统计意义上)是选择最优行动,所以第11步的ensemble average reward就应该是max(qstar),这就是第11步的平均奖励相比前10步(0零均值的)平均奖励大幅度提升的必然性。

        之后,从第11步到20步,由于最优行动被选择次数为2,而其它仍然为1,这就导致了其它9种行动在不确定性方面占据优势。如果这个优势相比行动价值估计值占据绝对优势的话(当前实验条件该满足这一条件),就必然导致第11步到20步又是对其余9种行动的轮询,因此其平均奖励又比第11步时的要下降,下降多少取决于各行动的奖励期望(qstar)相比max(qstar)差多少。 

     本系列总目录参见:强化学习笔记总目录 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笨牛慢耕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值