强化学习多臂老虎机介绍【Multi-armed Bandits】

强化学习笔记

主要基于b站西湖大学赵世钰老师的【强化学习的数学原理】课程,个人觉得赵老师的课件深入浅出,很适合入门.

第一章 强化学习基本概念
第二章 贝尔曼方程
第三章 贝尔曼最优方程
第四章 值迭代和策略迭代
第五章 强化学习实践—GridWorld
第六章 蒙特卡洛方法
第七章 Robbins-Monro算法
第八章 多臂老虎机



Bandit(老虎机、赌博机)问题是强化学习领域中的一个经典问题,老虎机是一种用于赌博的机器,下拉老虎机的机械手臂,我们可以随机获得一个奖励。在赌场中,我们常常能看见很多老虎机被摆在一排,我们可以选择去下拉其中任何一只手臂,获得一个随机奖励,显然我们的目标是最大化奖励。在强化学习中我们将这种背景的问题称为多臂老虎机(Multi-armed Bandits)问题,后面缩写为abd

一、问题描述

在abd问题中,每个老虎机的奖励值 r 的分布 P ( r ∣ a ) P(r|a) P(ra)​,它对于不同的老虎机来说是不同的,但是对某一台老虎机来说是固定的。比如是10-armed bandits,那么这个问题可以建模成如下的强化学习问题:

  • 动作空间 A \mathcal{A} A 0 , 1 , 2 , ⋯   , 9. 0,1,2,\cdots,9. 0,1,2,,9.
  • 奖励:通常设置为正太分布 r i ∼ N ( q i , 1 ) , i = 0 , 1 , 2 , ⋯   , 9. r_i\sim \mathcal{N}(q_i, 1),i=0,1,2,\cdots,9. riN(qi,1)i=0,1,2,,9.
  • 状态空间:显然这个问题是一个简化的MDP,可以视为没有状态空间.

如下图所示,10个老虎机的奖励分布都是方差为1的正太分布,但是均值不同。

截屏2024-04-23 19.16.20

我们在一开始是不知道每台老虎机的奖励分布 P ( r ∣ a ) P(r|a) P(ra)(模型未知),而只能通过不断的实验和尝试来增进对分布的了解。假设我们实验n次,在每一次选择一个动作 A t ∈ A A_t\in\mathcal{A} AtA,然后得到一个奖励 R t ∼ r i R_t\sim r_i Rtri,得到如下的序列:
A 1 , R 1 , A 2 , ⋯   , A n , R n . A_1,R_1,A_2,\cdots,A_n,R_n. A1,R1,A2,,An,Rn.我们的目标是最大化累积回报:
G n = ∑ t = 1 n R t . G_n=\sum_{t=1}^{n}R_t. Gn=t=1nRt.所以关键的问题是如何学习一个策略,使得尽量多的选择回报值更高的bandit,而这里就又涉及到ExplorationExploitation的问题了。因为当n给定时,想要获得最大累积回报,是尽可能多的利用当前信息选择最优动作,还是多探索了解更多的信息呢,这也是不同算法所关心的问题。

二、动作值函数的估计

显然在abd问题中,我们需要估计 q ( s , a ) q(s,a) q(s,a),但这个问题没有 s s s,所以可以简记为 q ( a ) q(a) q(a)。通过前面介绍的Monte-calro方法(蒙特卡洛方法),我们自然地可以想到用均值 Q n ( a ) Q_n(a) Qn(a)来近似期望 q ( a ) q(a) q(a)
Q n ( a ) ≐ 在时间 n 前选择动作 a 的奖励值的总和 在时间 n 前动作 a 被选择的次数 = ∑ i = 1 n − 1 R i ⋅ 1 A i = a ∑ i = 1 n − 1 1 A i = a , Q_n(a)\doteq\frac{\text{在时间 n 前选择动作 a 的奖励值的总和}}{\text{在时间 n 前动作 a 被选择的次数}}=\frac{\sum_{i=1}^{n-1}R_i\cdot\mathbb{1}_{A_i=a}}{\sum_{i=1}^{n-1}\mathbb{1}_{A_i=a}}, Qn(a)在时间 n 前动作 a 被选择的次数在时间 n 前选择动作 a 的奖励值的总和=i=1n11Ai=ai=1n1Ri1Ai=a,其中 1 x \mathbb{1}_x 1x 的值在 x x x 为真时为 1, 否则为 0。我们来看单个老虎机的 Q n ( a ) Q_n(a) Qn(a)怎么计算:
Q n + 1 ( a ) ≐ R 1 + R 2 + ⋯ + R n n . Q_{n+1}(a)\doteq\frac{R_1+R_2+\cdots+R_{n}}{n}. Qn+1(a)nR1+R2++Rn.
由前面介绍的Robbins-Monro算法,我们知道上式可以写成迭代的格式:
Q n + 1 ( a ) = Q n ( a ) − 1 n ( Q n ( a ) − R n ) ( 1 ) Q_{n+1}(a)=Q_n(a)-\frac1n(Q_n(a)-R_n) \qquad(1) Qn+1(a)=Qn(a)n1(Qn(a)Rn)(1)其中 Q 1 Q_1 Q1是初始给定的,迭代的形式可以减少内存和计算的消耗。由RM算法我们知道,如果我们有无限的时间步长,那么就可以保证 Q n ( a ) Q_n(a) Qn(a) 收敛为 q ( a ) q(a) q(a)。我们知道(1)式更一般的形式如下:
Q n + 1 = Q n − α n ( Q n − R n ) , ( 2 ) Q_{n+1}=Q_n-\alpha_n(Q_n-R_n),\qquad(2) Qn+1=Qnαn(QnRn),(2)其中 a n a_n an为步长参数,由RM算法我们知道,要使算法收敛 a n a_n an需要满足:
∑ 1 ∞ α n = ∞ , ∑ 1 ∞ α n 2 < ∞ . ( 3 ) \sum_1^\infty\alpha_n=\infty, \qquad\sum_1^\infty\alpha_n^2<\infty.\qquad(3) 1αn=,1αn2<∞.(3) α n = 1 n \alpha_n=\frac1n αn=n1是满足上述条件的,但是这种取法是比较适合平稳的abd问题,也就是说每个老虎机的奖励分布不随时间改变。但是我们经常会遇到非平稳的强化学习问题,在这种情况下,给予近期奖励比过往奖励更大的权重是更合适的,最流行的方法之一是使用恒定的步长参数,即:
Q n + 1 = Q n − α ( Q n − R n ) , ( 4 ) Q_{n+1}=Q_n-\alpha(Q_n-R_n),\qquad(4) Qn+1=Qnα(QnRn),(4)通过递推,可以得到:
Q n + 1 = Q n + α ( R n − Q n ) = α R n + ( 1 − α ) Q n = α R n + ( 1 − α ) [ α R n − 1 + ( 1 − α ) Q n − 1 ] = α R n + ( 1 − α ) α R n − 1 + ( 1 − α ) 2 Q n − 1 = α R n + ( 1 − α ) α R n − 1 + ( 1 − α ) 2 α R n − 2 + ⋯ + ( 1 − α ) n − 1 α R 1 + ( 1 − α ) n Q 1 = ( 1 − α ) n Q 1 + ∑ i = 1 n α ( 1 − α ) n − i R i . \begin{aligned} Q_{n+1} &= Q_{n}+\alpha(R_{n}-Q_{n}) \\ &=\alpha R_n+(1-\alpha)Q_n \\ &=\alpha R_n+(1-\alpha)\left[\alpha R_{n-1}+(1-\alpha)Q_{n-1}\right] \\ & =\alpha R_{n}+(1-\alpha)\alpha R_{n-1}+(1-\alpha)^{2}Q_{n-1} \\ &=\alpha R_n+(1-\alpha)\alpha R_{n-1}+(1-\alpha)^2\alpha R_{n-2}+ \\ &\qquad\cdots+(1-\alpha)^{n-1}\alpha R_1+(1-\alpha)^nQ_1 \\ &=(1-\alpha)^nQ_1+\sum_{i=1}^n\alpha(1-\alpha)^{n-i}R_i. \end{aligned} Qn+1=Qn+α(RnQn)=αRn+(1α)Qn=αRn+(1α)[αRn1+(1α)Qn1]=αRn+(1α)αRn1+(1α)2Qn1=αRn+(1α)αRn1+(1α)2αRn2++(1α)n1αR1+(1α)nQ1=(1α)nQ1+i=1nα(1α)niRi.注意到 ( 1 − α ) n + ∑ i = 1 n α ( 1 − α ) n − i = 1 (1-\alpha)^n+\sum_{i=1}^n\alpha(1-\alpha)^{n-i}=1 (1α)n+i=1nα(1α)ni=1,所以 Q n + 1 Q_{n+1} Qn+1可以看作 Q 1 , R 1 , ⋯   , R n Q_1,R_1,\cdots,R_n Q1,R1,,Rn的加权和,距离最近的 R n R_n Rn有更大的权值,时间过去较久的 Q 1 , R 1 Q_1,R_1 Q1,R1等权值越来越小。(4)式不满足(3)的条件,所以 Q n Q_n Qn不会严格收敛到 q ( a ) q(a) q(a),但是我们可以证明 E [ Q n ] = q ( a ) \mathbb{E}[Q_n]=q(a) E[Qn]=q(a),对(4)两边取期望,可得:
E [ Q n + 1 ] = ( 1 − α ) E [ Q n ] + α E [ R n ] . \mathbb{E}[Q_{n+1}]=(1-\alpha)\mathbb{E}[Q_n]+\alpha\mathbb{E}[R_n]. E[Qn+1]=(1α)E[Qn]+αE[Rn]. R 1 , ⋯   , R n R_1,\cdots,R_n R1,,Rn是关于同一个老虎机采样得到的独立同分布样本,不妨设 E [ R n ] = r \mathbb{E}[R_n]=r E[Rn]=r,并记 q n = E [ Q n + 1 ] q_n=\mathbb{E}[Q_{n+1}] qn=E[Qn+1],那么我们有:
∣ q n + 1 − r ∣ = ∣ α r + ( 1 − α ) q n − r ∣ = ∣ ( 1 − α ) ( q n − r ) ∣ ⋮ = ∣ ( 1 − α ) n ( q 1 − r ) ∣ ≤ ∣ 1 − α ∣ n ∣ q 1 − r ∣ \begin{aligned} |q_{n+1}-r|&=|\alpha r+(1-\alpha)q_n-r|\\ &=|(1-\alpha)(q_n-r)|\\ &\quad\vdots\\ &=|(1-\alpha)^n(q_1-r)|\\ &\leq|1-\alpha|^n|q_1-r| \end{aligned} qn+1r=αr+(1α)qnr=(1α)(qnr)=(1α)n(q1r)∣1αnq1r显然如果当 ∣ 1 − α ∣ < 1 |1-\alpha|<1 ∣1α<1时,上式右端会趋于0,也就是说当 0 < α < 2 0<\alpha<2 0<α<2时,我们有:
E [ Q n ] = r . \mathbb{E}[Q_n]=r. E[Qn]=r.所以我们用迭代法进行估计仍然是可行的。当然上面这个推导是针对Stationary的情况,Nonstationary的情况更复杂,这里就不展开了。第五节我们通过实验可以发现在非平稳情况下, α \alpha α取固定值的效果确实更好!

三、 ϵ \epsilon ϵ-greedy策略

通过前面几章的学习我们知道,贪心策略可以写成:
A t = arg ⁡ max ⁡ a Q t ( a ) A_t=\arg\max_aQ_t(a) At=argamaxQt(a)然而,我们也可以把这个贪心策略转化成有一定探索性的策略,即让它以 ϵ \epsilon ϵ 的概率去探索其他动作,也就是 ϵ \epsilon ϵ-greedy策略:
A t = { a random action with probability  ϵ , arg ⁡ max ⁡ a Q t ( a ) with probability  1 − ϵ . A_t=\begin{cases} \text{a random action}& \text{with probability $\epsilon$} , \\ \arg\max_aQ_t(a) & \text{with probability $1-\epsilon$} . \end{cases} At={a random actionargmaxaQt(a)with probability ϵ,with probability 1ϵ.

下面我们实现 ϵ \epsilon ϵ-greedy策略,并看看不同的 ϵ \epsilon ϵ值有什么影响.

import numpy as np
import matplotlib.pyplot as plt

# create k-armed bandit
def k_abd(k):
    q_mean = np.random.normal(0, 1, k)
    return q_mean

def play(epsilon,q_mean):

    k = len(q_mean) # number of bandits
    
    reward = []
    total_reward = 0
    optimal_action_percentage = []
    N = np.zeros(k) # number of times each bandit was chosen
    Q = np.zeros(k) # estimated value
    optimal_action = 0
    optimal_index = np.argmax(q_mean)  # calculate optimal index once
    for i in range(2000):
        
        # epsilon greedy
        if np.random.rand() < epsilon:
            A = np.random.randint(k)
        else:
            A = np.argmax(Q)
        if A == optimal_index:
            optimal_action += 1
        R = np.random.normal(q_mean[A], 1)
        N[A] += 1
        Q[A] += (R - Q[A]) / N[A]
        total_reward += R
        reward.append(total_reward/(i+1))
        optimal_action_percentage.append(optimal_action/(i+1))
    return reward, optimal_action_percentage

k = 10
armed_bandit_10 = k_abd(k)
r1,qap1 = play(0,armed_bandit_10)
r2,qap2 = play(0.01,armed_bandit_10)
r3,qap3 = play(0.1,armed_bandit_10)

# plot
plt.figure(figsize=(10,5),dpi = 150)
plt.plot(r1,label='ε=0')
plt.plot(r2,label='ε=0.01')
plt.plot(r3,label='ε=0.1')
plt.legend()
plt.xlabel('Steps')
plt.ylabel('Average Reward')
plt.title('10-armed bandit problem')
plt.show()

plt.figure(figsize=(10,5),dpi = 150)
plt.plot(qap1,label='ε=0')
plt.plot(qap2,label='ε=0.01')
plt.plot(qap3,label='ε=0.1')
plt.legend()
plt.xlabel('Steps')
plt.ylabel('% Optimal Action')
plt.title('10-armed bandit problem')
plt.gca().yaxis.set_major_formatter(mtick.PercentFormatter(1)) 
plt.show()

下图显示了 ϵ \epsilon ϵ分别等于0,0.01,0.1时探索2000次的平均reward,我们可以看到贪心策略 ( ϵ = 0 ) (\epsilon=0) (ϵ=0)的平均奖励最低, ϵ = 0.01 \epsilon=0.01 ϵ=0.01时的平均奖励比 ϵ = 0.1 \epsilon=0.1 ϵ=0.1时高。因为 ϵ \epsilon ϵ-greedy策略理论上最后都能找到最优动作,当找到最优动作后, ϵ = 0.01 \epsilon=0.01 ϵ=0.01时,选择最优动作的概率为 p = 1 − ϵ ≈ 0.99 p=1-\epsilon\approx0.99 p=1ϵ0.99,而 ϵ = 0.1 \epsilon=0.1 ϵ=0.1时,选择最优动作的概率为 p ≈ 0.9 p\approx0.9 p0.9,所以 ϵ = 0.01 \epsilon=0.01 ϵ=0.01时的平均奖励更高。

10abd

下图则是在实验中每种情况下选择最优动作的概率,我们可以看到 ϵ = 0.01 \epsilon=0.01 ϵ=0.01时, p → 0.99 p\to0.99 p0.99,而 ϵ = 0.1 \epsilon=0.1 ϵ=0.1时, p → 0.9 p\to0.9 p0.9.

10abd_p

四、UCB算法

由于动作价值估计的准确性总是存在不确定性,因此需要进行Exploration。贪心算法总是利用当前信息选择最优动作的算法,但实际上其他动作可能更好。 ϵ \epsilon ϵ-greedy策略有一定概率尝试其他动作,但不加区分,对那些接近贪婪或特别不确定的行动没有偏好。最好根据它们实际成为最优动作的潜力在非贪婪行动中进行选择,同时考虑它们的估计与最大值的接近程度以及这些估计中的不确定性。一个有效的方法是UCB算法,这里我们直接给出其策略更新公式(推导可以参考文献2):
A t ≐ arg ⁡ max ⁡ a [ Q t ( a ) + c ln ⁡ t N t ( a ) ] , A_t\doteq\arg\max_a\left[Q_t(a)+c\sqrt{\frac{\ln t}{N_t(a)}}\right], Atargamax[Qt(a)+cNt(a)lnt ],
Python实现如下:

def play_ucb(c, q_mean):
    k = len(q_mean)  # number of bandits
    reward = []
    total_reward = 0
    N = np.zeros(k)  # number of times each bandit was chosen
    Q = np.zeros(k)  # estimated value

    for i in range(1, 2001):  # start from 1 to avoid division by zero in UCB calculation
        if np.min(N) == 0:
            # If any action has not been taken yet, take it to initialize all actions
            A = np.argmin(N)
        else:
            ucb_values = Q + c * np.sqrt(np.log(i) / N)
            A = np.argmax(ucb_values)
        
        R = np.random.normal(q_mean[A], 1)
        N[A] += 1
        Q[A] += (R - Q[A]) / N[A]
        total_reward += R
        reward.append(total_reward / i)

    return reward
rewards = play_ucb(2, armed_bandit_10)  # Example usage with c = 2
# plot reward
plt.figure(figsize=(10,5),dpi = 200)
plt.plot(rewards,label='UCB c=2')
plt.plot(r3,label='ε=0.1')
plt.xlabel('Steps')
plt.ylabel('Average Reward')
plt.title('10-armed bandit problem')
plt.legend()
plt.show()

下图展示了采用UCB算法和采用 ϵ = 0.1 \epsilon=0.1 ϵ=0.1 ϵ \epsilon ϵ-greedy算法的对比,可以看到UCB算的表现更好。

ucb

五、 非平稳老虎机

在上面我们提到对 Q n Q_n Qn迭代更新时, α n = 1 n \alpha_n=\frac1n αn=n1是比较适合平稳的abd问题,也就是说每个老虎机的奖励分布不随时间改变。但是我们经常会遇到非平稳的强化学习问题,在这种情况下,给予近期奖励比过往奖励更大的权重是更合适的,最流行的方法之一是使用恒定的步长参数。下面我们来验证一下是否是这样,我们考虑每个老虎机的 q q q每一步会有一个 N ( 0 , 0.01 ) \mathcal{N}(0,0.01) N(0,0.01)的噪声,代码如下:

import numpy as np
import matplotlib.pyplot as plt

# all bandits have the same initial q value
def initialize_q_means(k):
    return np.zeros(k)

# update q values with random noise
def update_q_means(q_means):
    return q_means + np.random.normal(0, 0.01, size=q_means.shape)

def simulate_bandit(k, steps, epsilon, alpha=None):
    q_means = initialize_q_means(k)
    rewards = {'sample_average': [], 'constant_step': []}
    optimal_action_counts = {'sample_average': [], 'constant_step': []}
    Q_sa = np.zeros(k)  # Q values for sample average
    Q_cs = np.zeros(k)  # Q values for constant step
    N = np.zeros(k)  
    
    total_rewards = {'sample_average': 0, 'constant_step': 0}
    optimal_actions = {'sample_average': 0, 'constant_step': 0}

    for step in range(steps):
        q_means = update_q_means(q_means)
        optimal_action = np.argmax(q_means)
        
        for strategy in ['sample_average', 'constant_step']:
            if np.random.rand() < epsilon:
                action = np.random.randint(k)
            else:
                if strategy == 'sample_average':
                    action = np.argmax(Q_sa)
                else:
                    action = np.argmax(Q_cs)
            
            reward = np.random.normal(q_means[action], 1)
            total_rewards[strategy] += reward
            if action == optimal_action:
                optimal_actions[strategy] += 1
            
            if strategy == 'sample_average':
                N[action] += 1
                Q_sa[action] += (reward - Q_sa[action]) / N[action]
            else:
                # constant step size, alpha = 0.1
                Q_cs[action] += alpha * (reward - Q_cs[action])

            rewards[strategy].append(total_rewards[strategy] / (step + 1))
            optimal_action_counts[strategy].append(optimal_actions[strategy] / (step + 1))
    
    return rewards, optimal_action_counts

# parameters
k = 10  
steps = 10000
epsilon = 0.1
alpha = 0.1

# simulate
rewards, optimal_action_counts = simulate_bandit(k, steps, epsilon, alpha)

# plot
plt.figure(figsize=(10, 8), dpi=150)
plt.subplot(2, 1, 1)
plt.plot(rewards['sample_average'], label='Sample Average')
plt.plot(rewards['constant_step'], label='Constant Step (alpha=0.1)')
plt.title('Average Rewards')
plt.xlabel('Steps')
plt.ylabel('Average Reward')
plt.legend()

plt.subplot(2, 1, 2)
plt.plot(optimal_action_counts['sample_average'], label='Sample Average')
plt.plot(optimal_action_counts['constant_step'], label='Constant Step (alpha=0.1)')
plt.title('Optimal Action Percentage')
plt.xlabel('Steps')
plt.ylabel('Optimal Action %')
plt.legend()

plt.tight_layout()
plt.show()

我们可以得到如下的结果,我们发现确实 α \alpha α取固定步长,比取 α n = 1 n \alpha_n=\frac1n αn=n1效果要好。

output

以下是固定步长参数 α \alpha α 效果更好的原因:

  1. 非静态问题的特点是环境的行为(或潜在的奖励分布)随时间改变。当使用固定的 α \alpha α 时,每次估计给予最新的奖励更大的权重,并逐渐忘记旧的奖励信息。这意味着估计的值能够快速适应环境的变化。而取平均值,则会随着时间逐渐给予历史奖励更多的权重,导致对环境变化的反应迟缓。
  2. 数学上的偏差-方差权衡
    固定的 α \alpha α为估计带来了更高的偏差,但在变化的环境中减少了方差,使得估计更稳定。采样平均方法虽然理论上在静态问题中可以收敛到真实值,但在非静态问题中可能会由于累积了太多过时的信息而导致高方差,使得算法性能下降。

总之,固定的步长 α \alpha α在处理需要快速反应的非静态环境中通常更为适合,因为它允许模型更快地适应最新的环境变化,而不是在老旧数据上花费太多计算资源。这在设计强化学习算法时是一个重要的考量,特别是在那些环境状态快速变化的应用场景中。

六、总结

本节我们介绍了强化学习中的老虎机问题,并介绍了解决老虎机问题的两种经典算法: ϵ \epsilon ϵ-greedy算法和UCB算法,前者是我们在Monte-Carlo方法中介绍过的。同时通过Python实现了这两种算法,实现这两个算法可以加深我们对蒙特卡洛思想以及RM算法在强化学习中的应用的理解,在这个问题中,我们用蒙特卡洛的思想以及RM算法来估计 q ( a ) q(a) q(a),进而进行策略优化。

同时我们还探讨了RM算法中步长 α \alpha α取值对与平稳问题和平稳问题的影响,验证了对与非平稳问题 α \alpha α取固定值更好的结论。

当然关于老虎机问题研究和具体应用还有非常多,具体可以参考文献2.

七、参考文献

  1. Sutton, Richard S., and Andrew G. Barto. Reinforcement learning: An introduction. MIT press, 2018.
  2. Lattimore, Tor, and Csaba Szepesvári. Bandit algorithms. Cambridge University Press, 2020.
  • 29
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值