强化学习2——多臂老虎机(下)

博客围绕探索与利用的决策平衡展开,介绍了贪心算法,如 ϵ−Greedy 算法及线性贪婪算法,可随时间改变探索概率。还阐述了上置信界算法,引入不确定度概念,利用霍夫丁不等式,选取期望奖励上界最大的动作,以实现累积奖励最大化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于探索与利用的决策与平衡

探索exploration:尝试拉动更多可能的拉杆,尽管这个拉杆不一定会获得最大的奖励,但是可以获取所有拉杆的获奖概率,知道哪根杠杆具有最大的获奖概率。

利用exploitation:拉动已知期望奖励最大的拉杆,但该信息仅来自于有限的交互观测,所以当前的最优拉杆不一定是全局最优。

设计策略时就需要平衡探索和利用的次数,使得累积奖励最大化。

贪心算法

ϵ−Greedy\epsilon -GreedyϵGreedy 算法,每次以概率 1−ϵ1-\epsilon1ϵ 选择以往经验中期望奖励估值最大的杠杆(对应利用),以概率ϵ\epsilonϵ 随机选择一根杠杆(探索),则公式表达为:

at={arg⁡max⁡a∈AQ^(a),采样概率:1−ϵ从 A中随机选择,采样概率:ϵ a_t=\begin{cases}\arg\max_{a\in\mathcal{A}}\hat{Q}(a),&{采样概率:1-\epsilon }\\\text{从 }\mathcal{A}\text{中随机选择},&{采样概率:\epsilon}\end{cases} at={argmaxaAQ^(a), A中随机选择,采样概率:1ϵ采样概率:ϵ

随着探索次数的增多,我们对各杠杆的获奖概率估计的越来越准,则可降低在探索上的投入,则可以降低ϵ\epsilonϵ 的大小,因此可以将ϵ\epsilonϵ 与时间绑定,随时间衰减,但其不会降低到零。

线性贪婪算法

class EpsilonGreedy(Solver):
    # ϵ-greedy算法
    def __init__(self,bandit,epsilon=0.01,initProb=1.0):
        super(EpsilonGreedy,self).__init__(bandit)
        self.epsilon=epsilon
        self.estimates=np.array([initProb]*self.bandit.K) #初始化每个拉杆的估计概率
    def runOneStep(self):
        # 选择探索还是利用
        if np.random.random()<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.0/(self.counts[k]+1)*(r-self.estimates[k]) #更新估计概率
        return k

def plotResults(solvers,solverNames):
    # 输入solvers是一个列表,列表中的每个元素是一种特定的策略(存储的数据也是以列表的形式)
    # 而solver_names也是一个列表,存储每个策略的名称
    for idx,solver in enumerate(solvers):
        timeList=range(len(solver.regrets))
        plt.plot(timeList,solver.regrets,label=solverNames[idx])
    plt.xlabel('Time')
    plt.ylabel('Cumulative regret')  
    plt.title('%d armed bandit'% solvers[0].bandit.K)
    plt.legend()
    plt.show()

np.random.seed(0)
K=10
bandit10Arm=BernoullBandit(K)
epsilons = [1e-4, 0.01, 0.1, 0.25, 0.5]
epsilon_greedy_solver_list = [
    EpsilonGreedy(bandit10Arm, epsilon=e) for e in epsilons
]
epsilon_greedy_solver_names = ["epsilon={}".format(e) for e in epsilons]
for solver in epsilon_greedy_solver_list:
    solver.run(5000)
plotResults(epsilon_greedy_solver_list, epsilon_greedy_solver_names)

image.png

随时间改变探索的概率

可以采用 ϵ\epsilonϵ 随时间衰减,可以采用反比例衰减,为 ϵt=1t\epsilon _t=\frac{1}{t}ϵt=t1

上置信界算法

引入不确定度 U(a)U(a)U(a) 的概念,当一根拉杆被拉动的次数比较少时,他的奖励概率的不确定性更高,更越有探索的价值。

上置信界UCB算法用到了霍夫丁不等式X1,...,XnX_1,...,X_nX1,...,Xn 为n个独立同分布的随机变量,取值范围为[0,1] ,经验期望为 x‾n=1n∑j=1nXj\overline x_n=\frac{1}{n} \sum _{j=1}^{n}X_jxn=n1j=1nXj ,则有:
P(E[X]≥x‾n+u)≤e−2nu2 P(E[X]\geq\overline x_n +u ) \leq e^{-2nu^2} P(E[X]xn+u)e2nu2
将动作a的期望奖励估值 Q^t(a)\hat Q_t(a)Q^t(a) 带入 x‾t\overline x_txt (同为期望,则可以获得下面的不等式) ,并将 u=U^t(a)u=\hat U_t(a)u=U^t(a) 代表不确定度,可以得到
P{Qt(a)≥Q^t(a)+U^t(a)}≤p=e−2Nt(a)Ut(a)2 P\{Q_t(a) \geq \hat Q_t(a)+\hat U_t(a)\} \leq p=e^{-2N_t(a)U_t(a)^2} P{Qt(a)Q^t(a)+U^t(a)}p=e2Nt(a)Ut(a)2

那么会以1-p的概率发生 Qt(a)≤Q^t(a)+U^t(a)Q_t(a) \leq \hat Q_t(a)+\hat U_t(a)Qt(a)Q^t(a)+U^t(a)Q^t(a)+U^t(a)\hat Q_t(a)+\hat U_t(a)Q^t(a)+U^t(a) 则为期望奖励上线,此时,上置信界算法便选取期望奖励上界最大的动作 a=argmax[Q^t(a)+U^t(a)]a=argmax[\hat Q_t(a)+\hat U_t(a)]a=argmax[Q^t(a)+U^t(a)] ,可以根据 p=e−2Nt(a)Ut(a)2p=e^{-2N_t(a)U_t(a)^2}p=e2Nt(a)Ut(a)2 计算得到:
U^t(a)=−log⁡p2Nt(a). \hat{U}_t(a)=\sqrt{\frac{-\log p}{2N_t(a)}}. U^t(a)=2Nt(a)logp.
更直观地说,UCB 算法在每次选择拉杆前,先估计每根拉杆的期望奖励的上界,使得拉动每根拉杆的期望奖励只有一个较小的概率超过这个上界接着选出期望奖励上界最大的拉杆,从而选择最有可能获得最大期望奖励的拉杆。

p=1tp=\frac{1}{t}p=t1 ,并设置不确定性的比重 a=arg⁡max⁡a∈AQ^(a)+c⋅U^(a)a=\arg\max_{a\in\mathcal{A}}\hat{Q}(a)+c\cdot\hat{U}(a)a=argmaxaAQ^(a)+cU^(a) ,同时,为了避免不确定度出现分母为0的情况,在分母+1。

class UCB(Solver):
    """ UCB算法,继承Solver类 """
    def __init__(self, bandit, coef, init_prob=1.0):
        super(UCB, self).__init__(bandit)
        self.total_count = 0
        self.estimates = np.array([init_prob] * self.bandit.K)
        self.coef = coef

    def runOneStep(self):
        self.total_count += 1
        ucb = self.estimates + self.coef * np.sqrt(
            np.log(self.total_count) / (2 * (self.counts + 1)))  # 计算上置信界
        k = np.argmax(ucb)  # 选出上置信界最大的拉杆
        r = self.bandit.step(k)
        self.estimates[k] += 1. / (self.counts[k] + 1) * (r - self.estimates[k])
        return k
  
np.random.seed(1)
coef = 1  # 控制不确定性比重的系数
K=10
bandit10Arm=BernoullBandit(K)
UCBSolver = UCB(bandit10Arm, coef)
UCBSolver.run(5000)
print('上置信界算法的累积懊悔为:', UCBSolver.regret)
plotResults([UCBSolver], ["UCB"])

image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值