北京时间 9 月 13 日午夜,OpenAI 正式公开一系列全新 o1大模型,旨在专门解决难题。这是一个重大突破,新模型可以实现复杂推理,一个通用模型解决比此前的科学、代码和数学模型能做到的更难的问题。
秘密武器在于强化学习和思维链。OpenAI 的大规模强化学习算法,教会模型如何在数据高度有效的训练过程中利用其思想链进行高效思考。
思维链见之前的文章:COT思维链,TOT思维树,GOT思维图,这些都是什么?
下面我们用最简单的语言,解释下强化学习中的基本思想: Exploit and Explore.
本文的原标题是《用Exploit and Explore解决不知道吃什么的选择困难症》,昨晚Open AI 发布了o1大模型,我这个小V也想蹭一下热度,希望泼天的流量能到我碗里一些...
1. 场景
又到周末了,你和女朋友出来约会,到了饭点你们开始纠结去哪里吃饭。这时候,经典的对话就出现了:
你:笨笨,今天你想吃什么?
她:随便呀,你定吧。
你:那我们吃火锅吧,上次的我觉得很好吃?
她:不要啦,火锅味太重了,我昨晚刚洗的头发呢。(撩起头发给你闻,香不香)
你:那吃烤肉吧,那边新开了一家烤肉?
她:不行啦,烤肉也有味道,我可是刚洗了头发的!生气!(撅着嘴巴)
你:那吃日料吧,上次的那家...
她:唔,上次那家不好吃,三文鱼都不知道是不是虹鳟(嘟起嘴)
你:那吃西餐吧?
她:哎呀,西餐太贵啦,我们还是省点吧,别告诉我你想的是必胜客!(挥舞小拳头)
你:那吃川菜吧,这边新开了一家辛香汇...
她:不行不行,川菜太辣了,你看我这里都长痘痘了!(把她的右脸转向你指给你看)
下面,让我们用Exploit and Explore策略帮你终结选择困难症。
2. Exploit and Explore
利用与探索策略是一种在推荐系统/强化学习中常用的策略,用于在已知的最优策略和未知的最优策略之间进行权衡。在谈恋爱的场景中,我们可以将Exploit and Explore策略应用于解决待会儿去哪吃饭的问题。
最简单的方案是:
-
我们以1-ϵ的概率选择她最喜欢的餐厅;
-
以ϵ的概率从全部的餐厅中随机选择一个。
这样,我们就可以在已知的最优策略和未知的最优策略之间进行权衡。
问题是,这有什么理论依据吗?
3. 多臂老虎机问题
把女朋友和老虎放在一起谈似乎怪怪的
多臂老虎机问题(Multi-armed bandit, MAB): 赌场内,有一名赌徒想要去摇老虎机(bandit),他面前有一排机器,每台机器都拥有一个臂(arm),而且每台机器看上去都一样。每次投一枚游戏币就能获得一次摇臂(play) 的机会,而且每个臂摇下都有可能吐出一枚硬币,即 奖励(rewards).
但是,每台老虎机吐出硬币的概率分布是未知的。作为赌徒,自然希望自己的累积收益的期望(expected cumulative reward)最大化(假如一共有n次摇臂的机会),那么,请问这名赌徒应该采取怎样的行动?
目前的解决方案不外乎以下几种:
- ϵ-贪心算法
- UCB算法
- Thompson Sampling算法
4. ϵ-贪心算法
每次以1−ϵ的概率选择以往经验中期望奖励估值最大的那根拉杆(利用), 以ϵ的概率随机选择一根拉杆(探索)
import numpy as np
def epsilon_greedy(q, epsilon):
"""ϵ-贪心算法
参数:
q -- 一个列表,表示每个动作的价值
epsilon -- ϵ 值,表示进行随机动作的概率
返回:
选择的动作的索引
"""
if np.random.random() < epsilon: # 以 ϵ 的概率选择一个随机动作
return np.random.choice(len(q))
else: # 以 1-ϵ 的概率选择当前最优的动作
return np.argmax(q)
5. UCB算法
一根拉杆只被拉动过一次,那么它的不确定性很高,进而其探索的价值高。为此,引入不确定性度量U(a),它会随着一个动作被尝试的次数的增加而减小。进而,我们可以使用一种基于不确定性的策略来综合考虑现有的期望奖励估值和不确定性,核心问题是如何估计不确定性。
上置信界(upper confidence bound, UCB)算法是一种经典的基于不确定性的策略方法,它的思想用到来了著名的数学原理:霍夫丁不等式。
5.1 霍夫丁不等式
霍夫丁不等式是概率论中的一个重要不等式,它描述了一个随机变量的和其期望值的偏离程度。霍夫丁不等式的一个重要应用是在估计一个随机变量的上界。
其中,P 表示概率。霍夫丁不等式说明当 N 很大的时候,v 与 u 相差不会很大,它们之间的差值被限定在ϵ 之内。
UCB算法通过计算每个臂的置信上界来做出选择,置信上界是臂的当前平均奖励加上一个与该臂被选择次数成反比的探索项。这个探索项通常使用一个称为“探索-利用权衡”的参数来控制,这个参数随着臂被选择的次数增加而减小。
算法的步骤大致如下:
- 初始化每个臂的奖励估计和选择次数。
- 对于每一步,计算每个臂的UCB值。
- 选择具有最高UCB值的臂。
- 观察所选臂的奖励,并更新该臂的奖励估计和选择次数。
- 重复步骤2-4直到满足终止条件(例如,达到一定的步数或时间)。
import numpy as np
class UCB:
def __init__(self, counts, values):
self.counts = counts
self.values = values
def select_arm(self):
n_arms = len(self.counts)
for arm in range(n_arms):
if self.counts[arm] == 0:
return arm
ucb_values = [0.0 for arm in range(n_arms)]
total_counts = sum(self.counts)
for arm in range(n_arms):
bonus = np.sqrt((2 * np.log(total_counts)) / float(self.counts[arm]))
ucb_values[arm] = self.values[arm] + bonus
return np.argmax(ucb_values)
def update(self, chosen_arm, reward):
self.counts[chosen_arm] = self.counts[chosen_arm] + 1
n = self.counts[chosen_arm]
value = self.values[chosen_arm]
new_value = ((n - 1) / float(n)) * value + (1 / float(n)) * reward
self.values[chosen_arm] = new_value
# 测试
ucb = UCB([0, 0, 0], [0.0, 0.0, 0.0])
chosen_arm = ucb.select_arm()
print(chosen_arm) # 输出: 选择的动作的索引
reward = np.random.rand() # 假设我们得到了一个随机的奖励
ucb.update(chosen_arm, reward)
6. Thompson Sampling算法
Thompson Sampling算法是一种基于贝叶斯推断的策略方法,它的核心思想是维护一个每个臂的奖励分布的后验概率分布。在每一步中,算法会从每个臂的后验分布中抽取一个样本,然后选择具有最高样本值的臂。
6.1 Beta分布
Beta 分布是定义在区间 [0,1] 上的连续概率分布,由两个参数 α(阿尔法)和 β(贝塔)控制其形状。Beta 分布是贝叶斯统计中常用的共轭先验分布,也是概率论和统计学中的一个重要工具。
Beta 分布的概率密度函数(PDF)为:
Beta函数的定义是:
Beta分布的均值和方差分别为:
6.2 Thompson Sampling算法
我们先假设每个拉杆的奖励服从一个特定的分布,然后根据每个拉杆的期望奖励来进行选择。但是由于计算每个拉杆的期望奖励计算代价比较高,汤普森采样算法使用采样的方式,即根据当前每个动作的奖励分布进行一轮采样,得到一组各个拉杆的奖励样本,再选择样本中奖励最大的动作。
我们可以看出,汤普森采样是一种计算每个拉杆产生最高奖励概率的蒙特卡罗采样方法。
了解了汤普森采样的基础思路后,需要解决另一个问题:当前每个动作的奖励分布怎样得到并且在过程中进行更新?在实际情况中,我们通常对当前每个动作的奖励分布用Beta分布进行建模。具体来说,若某拉杆选择了k次,其中m1次奖励为1,m2次奖励为0,则该拉杆的奖励服从参数为(m1+1,m2+1)的Beta分布.
import numpy as np
class ThompsonSampling:
def __init__(self, counts, values):
self.counts = counts # 记录每个动作的选择次数
self.values = values # 记录每个动作的总奖励
def select_arm(self):
n_arms = len(self.counts)
theta_values = [np.random.beta(self.values[arm] + 1, self.counts[arm] - self.values[arm] + 1) for arm in range(n_arms)]
return np.argmax(theta_values)
def update(self, chosen_arm, reward):
self.counts[chosen_arm] += 1
self.values[chosen_arm] += reward
# 测试
ts = ThompsonSampling([0, 0, 0], [0.0, 0.0, 0.0])
chosen_arm = ts.select_arm()
print(chosen_arm) # 输出: 选择的动作的索引
reward = np.random.rand() # 假设我们得到了一个随机的奖励
ts.update(chosen_arm, reward)
7. 总结
现在,你可以用Exploit and Explore策略选择餐厅不用再纠结了。
欢迎关注我的GitHub和微信公众号,来不及解释了,快上船!
[1] 统计机器学习 13:多臂老虎机
[2] 多臂老虎机:Multi-Armed Bandit:MAB
[3] wiki:霍夫丁不等式
欢迎关注我的GitHub和微信公众号:
仓库上有原始的Markdown文件,完全开源,欢迎大家Star和Fork!
公众号;真-忒修斯之船