深度学习(1)--多臂老虎Ji模型
探索与利用的平衡
\(\epsilon\) 贪心算法
在贪心采取每一时刻奖励估值最大的动作的基础上,加入了一个随机参数 \(\epsilon\) 。
每次以概率 $1-\epsilon $ 选择期望奖励最大的那个动作(利用),以概率 $\epsilon $ 来随机选取一根拉杆(探索)。
如果 $\epsilon $ 一直不变的话,最后的收益会一直存在一个无法收敛的累积懊悔(距离实际最优的差值)。所以让 \(\epsilon\) 按照一个速率来衰减,可以是反比例,也可以是 \(e^{-\lambda}\) 。
上置信界优化(Upper confidence bound)
基于不确定性的策略算法。前期的选择中,由于样本量太小使得统计的不确定性太大了,贪心选择的话会造成很大的偏差。
引入一个不确定性度量 \(U(a)\) ,它随着一个动作被尝试的次数增加而减小。使用这个不确定性度量和期望奖励来共同决定策略的选择。
霍夫丁不等式: \(X_1,X_2,\dots,X_n\) 为 \(n\) 个独立同分布的随机变量,取值范围为 \([0,1]\),其经验期望为 \(\bar{x} = \frac{1}{n} \sum_{j=1}^{n} X_j\), 则有 \(\mathbb{P}\{ \mathbb{E}[x] \ge \bar{x}_x + u \} \le e^{=2nu^2}\) 。
将霍夫丁不等式运用于多臂老虎Ji问题中。总操作 \(t\) 次之后,将操作 \(a\) 的期望奖励 \(\hat{Q}_t(a)\) 带入 \(\bar{x}_t\)。
根据上述不等式,$ Q_t < \hat{Q}(a) + \hat{U}_t(a)$ 至少以概率 \(1-p =1- e^{-2N_t(a)U(a)^2}\) 成立。
当 \(p\) 很小的时候,我们认为 $ Q_t < \hat{Q}(a) + \hat{U}_t(a)$ 以很大的概率成立,视 $ Q_t < \hat{Q}(a) + \hat{U}_t(a)$ 为期望奖励上界。实际操作的时候会给 \(\hat{U}_t(a)\) 乘上一个不确定度调节系数 \(c\) 。
UCB实际操作:
- 设置 \(p = \frac{1}{t}\),此时 \(\hat{U}_t(a) = \sqrt{\frac{ln(t)}{2(N_t(a)+1)}}\) ,此处的 \(N_t(a)+1\) 是为了防止分母为0的情形。
- 找出加权后的 \(\hat{Q}(a) + c \times \hat{U}(a)\) 最大的操作 \(a\) 。
- 执行操作 \(a\) 并更新 \(\hat{Q}_a\)
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 run_one_step(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 # 控制不确定性比重的系数
UCB_solver = UCB(bandit_10_arm, coef)
UCB_solver.run(5000)
print('上置信界算法的累积懊悔为:', UCB_solver.regret)
plot_results([UCB_solver], ["UCB"])
汤普森采样算法
使用采样的方式对每个动作 \(a\) 的奖励概率分布进行一次采样,得到的各个拉杆的奖励样本,再选择样本中奖励最大的动作。
实际情况中,我们使用 Beta 分布来对当前每个动作的奖励进行建模。每次拉杆成功和不成功视作一次 0-1 伯努利试验。
定义 Beta 函数为 \(B(x,y) = \int_0^1 t^{x-1}(1-t)^{y-1}dt\) 。
我们使用 Gemma 函数来计算 Beta函数 \(B(x,y) = \frac{\Gamma(x)\Gamma(y)}{\Gamma(x+y)}\) ,其中 Gamma 函数有很好的递推性质。
Beta 分布的概率密度函数 \(f(p;\alpha,\beta) = \frac{1}{B(\alpha, \beta) } p^{\alpha -1} (1-p)^{\beta -1}\), 其中的 \(p\) 为对真实成功率的一种预测,而 \(f\) 则是真实成功率为 \(p\) 的概率。
具体来说,如果某个拉杆被选择了 \(m_1+m_2\) 次 其中 \(m_1\) 次奖励为 \(1\) ,\(m_2\) 次奖励为 \(0\) 。这视作这个拉杆服从参数为 \((m_1+1,m_2+1)\) 的 Beta 分布。

初始分布为Beta(1,1),均匀分布;刚开始的时候每个操作的分布在高概率处都比较多,所以有比较高的概率被采样到(初期:探索的权重大);随着每个操作的采样数的上涨,分布会慢慢收拢,那些实际期望奖励小的操作的分布靠近 \(0\),实际期望奖励大的操作的分布靠近 \(1\)。所以实际期望奖励大的点在后期更有可能被采样到(后期:利用的权重大)。
这个方法比较优雅的实现了探索和利用的权衡。
class ThompsonSampling(Solver):
""" 汤普森采样算法,继承Solver类 """
def __init__(self, bandit):
super(ThompsonSampling, self).__init__(bandit)
self._a = np.ones(self.bandit.K) # 列表,表示每根拉杆奖励为1的次数
self._b = np.ones(self.bandit.K) # 列表,表示每根拉杆奖励为0的次数
def run_one_step(self):
samples = np.random.beta(self._a, self._b) # 按照Beta分布采样一组奖励样本
k = np.argmax(samples) # 选出采样奖励最大的拉杆
r = self.bandit.step(k)
self._a[k] += r # 更新Beta分布的第一个参数
self._b[k] += (1 - r) # 更新Beta分布的第二个参数
return k
np.random.seed(1)
thompson_sampling_solver = ThompsonSampling(bandit_10_arm)
thompson_sampling_solver.run(5000)
print('汤普森采样算法的累积懊悔为:', thompson_sampling_solver.regret)
plot_results([thompson_sampling_solver], ["ThompsonSampling"])

浙公网安备 33010602011771号