多臂老虎机
图1.多臂老虎机想象一下,你站在拉斯维加斯的赌场里,面前有一排(比如10台)老虎机。 每台机器的中奖率都不一样,有的容易吐钱,有的是“吞金兽”。但问题是——你不知道哪台是好的。你的口袋里只有有限的筹码(比如只能拉5000次)。
- 如果你每个都试一遍,太浪费机会(探索 Exploration);
- 如果你认准一台死磕,万一它不是最好的,你就亏大了(利用 Exploitation)。
这就是强化学习中最经典的“多臂老虎机问题”(Multi-Armed Bandit, MAB)。 今天,我们用 Python 手写三个“赌徒智能体”,看看谁能赢走最多的钱!👇
搭建环境 (The Environment)
首先,我们需要造一个赌场。 在代码中,我们定义一个 BernoulliBandit 类。这里的关键是 probs 属性——它是上帝视角,存着每一台机器真实的吐钱概率。
玩家只能通过 step(k) 来拉动摇杆,返回 1 (中奖) 或 0 (没中)。玩家看不到 probs,只能靠猜!
# 省略部分代码,只放核心
classBernoulliBandit:
def__init__(self, K):
self.probs = np.random.uniform(size=K) # 随机生成K个机器的真实概率
self.best_prob = self.probs[np.argmax(self.probs)] # 记下最好的那个,为了后面算账
评判标准:怎么算赢?
我们怎么知道算法好不好?看赚钱总数吗? 不,更专业的指标是“累积懊悔”(Cumulative Regret)。
- 定义:懊悔 = (最好的那台机器的概率 - 你选的那台机器的概率)。
- 人话:本来能拿100分,你选了个80分的机器,你就亏了20分。这个亏损加起来越少,算法越牛。
选手登场:三大策略详解 (The Algorithms)
选手一:犹豫的赌徒 (-Greedy)
这个策略很简单:抛硬币。
- 偶尔(乱选):闭着眼随便挑一台,万一发现新大陆呢?
💻 核心代码解析:
if np.random.random() < self.epsilon:
k = np.random.randint(0, self.bandit.K) # 偶尔瞎蒙
else:
k = np.argmax(self.estimates) # 平时挑最好的
缺点:就算到了后期,它还是会忍不住去乱试那些明知很差的机器。
选手二:盲目乐观派 (UCB)
Upper Confidence Bound(上界置信算法)。 它的信条是:“没被毒打过的机器,都是潜力股!”它在评分时,不仅看平均分,还加上一个“潜力分”(不确定性)。
💻 核心代码解析:
# 估计值 + 探索系数 * sqrt(log(总次数) / 玩这台机器的次数)
ucb = self.estimates + self.coef * np.sqrt(np.log(self.total_count) / (2 * (self.counts + 1)))
图2.置信区间的收窄过程
选手三:贝叶斯大神 (Thompson Sampling)
这是今天最强的算法:汤普森采样。 它不维护一个死板的平均值,而是维护一个概率分布(Beta分布)。
决策:每次从每台机器的分布里抽个签,谁抽出来的数大,就选谁。
💻 核心代码解析:这段代码利用了 Beta 分布的共轭特性,更新极快:
samples = np.random.beta(self._a, self._b) # 1. 抽签
k = np.argmax(samples) # 2. 选最大的
# 3. 更新分布参数
self._a[k] += r # 赢了加a
self._b[k] += (1 - r) # 输了加b
总结 (Conclusion)
为什么汤普森采样在推荐系统和广告领域这么火? 因为它优雅地解决了 Exploration-Exploitation Dilemma(探索与利用的困境)。它像一个有经验的智者,根据信心来调整尝试的步伐。
参考文章:https://hrl.boyuai.com/chapter/1/%E5%A4%9A%E8%87%82%E8%80%81%E8%99%8E%E6%9C%BA