阅读《强化学习与大模型推荐系统》应具备一定的深度学习和推荐系统技术基础,适合于对大模型和强化学习推荐技术感兴趣的读者学习参考。
《强化学习与大模型推荐系统》全书下载地址:https://github.com/ByShui/Book_RL-LLM-In-RS

强化学习推荐系统:不同的探索策略——UCB探索策略(4.3)

一个优秀的探索策略要能够同时满足探索和利用的需求,以下代码构造了一个具有5个动作的策略评估环境,以此来对不同探索策略的累计遗憾值进行分析:

class Bandit:
    def __init__(self, arm_count):
        self.arm_count = arm_count
        self.generate_arms()

    def generate_arms(self):
        self.arms = []
        for _ in range(self.arm_count):
            mean = np.random.normal(0, 1)
            std_dev = np.random.uniform(0.5, 1.5)
            self.arms.append((mean, std_dev))

    def reward(self, arm):
        mean, std_dev = self.arms[arm]
        return np.random.normal(mean, std_dev)

    def optimal_arm(self):
        return np.argmax([mean for mean, _ in self.arms])

if __name__ == "__main__":
    arm_count = 5
    bandit = Bandit(arm_count)

具体来说,策略评估环境中设置了5个臂,摇动臂的奖励 reward a \text{reward}_a rewarda服从不同的正态分布: reward a = N ( μ , σ ) \text{reward}_a=\mathcal{N}(\mu,\sigma) rewarda=N(μ,σ)其中, μ \mu μ σ \sigma σ分别是正态分布的均值和方差,它们是随机生成的。定义拥有最大均值的动作是最优动作 a ∗ a_* a,最优价值 V ∗ V_* V从最优臂的价值分布中采样得到。

优化策略需要牺牲短期利益,因为需要通过探索搜集更多的信息以获得更优的动作,使得智能体最终能够获得更多回报。探索和利用是强化学习中的一对矛盾体,这意味着在学习过程中,智能体需要在已知和未知的情况下做出最优的决策。

其中,利用是指在已知情况下选择已知最优的策略来获得收益,而探索是指在未知情况下,为了获取更多的信息和收益,选择不同的策略进行尝试。

探索是指在不确定性的环境中,探索新的策略或动作来获得更高的奖励或效用,包含两个部分:一是尝试未知的行为,以期找到更好的策略并更新模型;二是平衡已知和未知的行为,以确保不会错过可能的好策略。

在推荐系统中,探索可以包括推荐新的项目、向用户提供个性化的推荐建议或者探索不同的推荐策略(如多臂机)。探索和利用需要平衡,以确保推荐系统具有长期的优化效果。

一个标准的强化学习算法包括探索和利用两个步骤——探索帮助智能体充分了解其状态空间,利用则帮助智能体找到最优的动作序列。

用来平衡探索和利用的方法包括:贪心探索策略、高斯探索策略、UCB探索策略、玻尔兹曼探索策略、汤普森采样探索策略和熵正则化探索策略等,本篇博客我们介绍一下UCB(Upper Confidence Bound,置信区间上界)探索策略。

贪心探索策略请查看:强化学习推荐系统:不同的探索策略——贪心探索策略(4.1)
高斯探索策略请查看:强化学习推荐系统:不同的探索策略——高斯探索策略(4.2)

UCB探索策略

根据大数定律我们知道臂的价值均值会收敛到期望值,但前提是需要足够多的试验轮次。假设在2个不同臂组成的多臂机中,经过一段时间的探索后,2个臂当前的奖励分布如下图的实线和虚线所示。

在这里插入图片描述
上面这张图所示的奖励分布下选择哪一个臂更合适?大多数人依靠直觉会选择臂 a 2 a_2 a2,因为臂 a 2 a_2 a2对应的均值较高。但在实践中,如果试验轮次不足,那么很容易出现宽分布的臂 a 1 a_1 a1抽样得到的奖励大于窄分布的臂 a 2 a_2 a2抽样得到的奖励的现象。这是因为臂 a 1 a_1 a1的奖励具有较高的方差(即采样不确定性大),这使得右交点后的奖励也有较大的被采样概率。在这种情况下就需要更多地去尝试使用臂 a 1 a_1 a1,获取奖励以更准确地估计其价值,即尽可能缩小方差带来的影响。

综上可知,单纯用奖励均值来估计价值并依此选择后续摇臂的方法可能需要一个很长的探索过程才能收敛到准确结果,一种更加快速且准确的办法是利用UCB探索策略来指导臂的选择,令: a t = arg max ⁡ a ∈ A ( Q t ( a ) + U t ( a ) ) a_t=\argmax_{a\in A}(Q_t(a)+U_t(a)) at=aAargmax(Qt(a)+Ut(a))

上式中, Q t ( a ) + U t ( a ) Q_t(a)+U_t(a) Qt(a)+Ut(a)是臂 a a a价值的置信上界,通过在臂的价值 Q t ( a ) Q_t(a) Qt(a)的基础上加上置信误差 U t ( a ) U_t(a) Ut(a)构造得到。分布未知的置信上界可以根据霍夫丁不等式求得,有独立随机变量 X 1 , X 2 , . . . , X n X_1,X_2,...,X_n X1,X2,...,Xn,且 0 ≤ X t ≤ 1 0\leq X_t\leq 1 0Xt1 X ‾ t \overline{X}_t Xt为这些随机变量的均值, E [ X ] \mathbb{E}[X] E[X]为这些随机变量的期望值,则有不等式: P ( E [ X ] > X ‾ t + u ) ≤ e − 2 t u 2 P(\mathbb{E}[X]>\overline{X}_t+u)\leq \text{e}^{-2tu^2} P(E[X]>Xt+u)e2tu2

将该不等式代入多臂机问题中,可得:

P ( Q ( a ) > Q t ( a ) + U t ( a ) ≤ e − 2 N t ( a ) U t ( a ) 2 P(Q(a)>Q_t(a)+U_t(a)\leq \text{e}^{-2N_t(a)U_t(a)^2} P(Q(a)>Qt(a)+Ut(a)e2Nt(a)Ut(a)2

上式表示臂 a a a的价值 Q ( a ) Q(a) Q(a)大于置信上界的概率小于等于 e − 2 N t ( a ) U t ( a ) 2 \text{e}^{-2N_t(a)U_t(a)^2} e2Nt(a)Ut(a)2,取极值令 p = e − 2 N t ( a ) U t ( a ) 2 p=\text{e}^{-2N_t(a)U_t(a)^2} p=e2Nt(a)Ut(a)2,那么可以得到置信误差的表达式:

U t ( a ) = c log ⁡ t N t ( a ) U_t(a)=\sqrt{\frac{c\log t}{N_t(a)}} Ut(a)=Nt(a)clogt

由此得到了UCB探索策略:

a t = arg max ⁡ a ∈ A ( Q t ( a ) + U t ( a ) ) = arg max ⁡ a ∈ A ( Q t ( a ) + c log ⁡ t N t ( a ) ) \begin{aligned} a_t & =\argmax_{a\in A}(Q_t(a)+U_t(a)) \\ & = \argmax_{a\in A}(Q_t(a)+c\sqrt{\frac{\log t}{N_t(a)}}) \\ \end{aligned} at=aAargmax(Qt(a)+Ut(a))=aAargmax(Qt(a)+cNt(a)logt )

其中, Q t ( a ) Q_t(a) Qt(a)是动作的价值,Q_t(a)+c\sqrt{\frac{\log t}{N_t(a)}}是动作 a a a的置信上界, c c c是超参数, t t t是当前迭代的时间步, N t ( a ) N_t(a) Nt(a)是当前时间步之前臂 a a a被摇动的次数。可见,UCB探索策略由两项组成,第一项是利用,第二项是探索。在选择动作时,每次都选择置信上界最大(不确定性最大)的动作执行,随着执行的次数增多,动作的置信上界会收敛于其期望值,即:

Q t ( a ) + c log ⁡ t N t ( a ) → E [ r t ∣ A t = a ] Q_t(a)+c\sqrt{\frac{\log t}{N_t(a)}}\rightarrow\mathbb{E}[r_t | A_t=a] Qt(a)+cNt(a)logt E[rtAt=a]

从而达到从探索转为利用的目的,同时也使得遗憾值呈现与时间步的对数渐进关系。

如下代码实现了UCB探索策略:

def UCB(bandit, T, c=2):
    arm_count = bandit.arm_count
    Q = np.zeros(arm_count)
    N = np.zeros(arm_count)

    cumulative_regret = [0]
    for t in range(1, T+1):
        if t <= arm_count:
            arm = t - 1
        else:
            arm = np.argmax(Q + c * np.sqrt(np.log(t) / N))

        reward = bandit.reward(arm)
        N[arm] += 1
        Q[arm] += (reward - Q[arm]) / N[arm]

        optimal_reward = bandit.reward(bandit.optimal_arm())
        cumulative_regret.append(
            cumulative_regret[-1] + (optimal_reward - reward))

    return cumulative_regret

if __name__ == "__main__":
    arm_count = 5
    T = 1000
    bandit = Bandit(arm_count)

    cumulative_regret_UCB = UCB(bandit, T, c=2)

以上代码定义了UCB()方法,它接收三个参数:

  • bandit,一个多臂机实例;
  • T,试验轮次,即在多臂机上探索/利用多少轮;
  • c,超参数,用于平衡探索和利用的权重。

在每轮试验中,UCB探索策略都会为每个臂计算一个置信上界,然后选择具有最高上置信界的臂。下面这张图展示了UCB策略的探索过程,我们利用三个时间步(从左图到右图分别是 t 1 t_1 t1 t 2 t_2 t2 t 3 t_3 t3)来说明UCB具体是如何发挥作用的,其中,均值指的是 Q t ( a ) Q_t(a) Qt(a),置信上界指的是 Q t ( a ) + U t ( a ) Q_t(a)+U_t(a) Qt(a)+Ut(a)。可以观察到:

在这里插入图片描述

1)在 t t t=1时,臂1拥有最高的置信上界,这说明臂1的不确定性最大,因此选择臂1作为当前的动作;
2)在 t t t=2时,臂1的不确定性减小,此时臂5的不确定性最大,因此选择臂5作为当前的动作;
3)在 t t t=3时,臂5的不确定性减小,此时臂3的不确定性最大,应选择臂3作为当前动作。随着不确定性减小,均值会逐渐收敛到真实值。

更多推荐