我正在学习Sutton & Barto的《强化学习导论》第二章第七节,该节讨论了多臂老虎机问题中的梯度方法。(我知道第二版仍是草稿,章节可能会有些调整,但我的文件中第2.7节的标题是“梯度老虎机”。)我已经成功运用了第2.3至2.5节的方法,但使用梯度方法时,我总是得到一些令人困惑的结果。我将展示我的代码并举一个例子说明。
这里只是初始化所有内容:
import randomimport mathimport numpy as np, numpy.random# 臂的数量(k)和步长(alpha)k = 10alpha = 0.1# 初始化偏好函数(H)和奖励分布(R)H = {i: 0 for i in range(k)}R = {i: [random.uniform(-100,100), 1] for i in range(k)}
我使用的是静态奖励分布,并用字典来表示这些分布。我假设每个奖励都由高斯分布描述,因此我使用以下函数将动作映射到奖励:
def getReward(action, rewardDistribution): return random.gauss(rewardDistribution[action][0], rewardDistribution[action][1])
所谓的“偏好函数”H
,用于确定动作概率,也由字典给出。我将选择范围设得很广,因为每个奖励都是由标准差为1且位于-100到100之间的高斯分布描述的。我这样做是因为我的直觉告诉我这会使算法更难停留在次优选择上,但实际上情况恰恰相反。
以下是每次迭代中选择动作的代码:
def selectAction(policy): return np.random.choice(list(policy.keys()), p=list(policy.values()))
接下来是运行算法迭代的代码。请注意,pi
是策略,初始化时每个动作的概率为1/k
。
avgReward = 0for i in range(100000): pi = {i: math.exp(H[i])/sum([math.exp(H[j]) for j in range(k)]) for i in range(k)} A = selectAction(pi) R_A = getReward(A, R) avgReward += (R_A - avgReward)/(i + 1) H = {i: H[i] + alpha*(R_A - avgReward)*((i == A) - pi[i]) for i in range(k)}
请注意,我运行了100,000次迭代,这对我来说似乎已经足够了。这是我的第一次尝试,所以我的直觉可能有误,但我试图设置这个算法,使其更容易找到最优选择。因此,我期望这个过程会收敛到期望值最高的分布对应的动作,并在迭代过程中持续选择它。但是,当我打印出老虎机每个可能动作的结果时,我看到的是这样的情况:
for i in range(k): print("Expected reward: " + str(R[i][0]) + " | Selection probability: " + str(pi[i]) + " | Preference: " + str(H[i]))Expected reward: -50.62506110888989 | Selection probability: 3.617077909489526e-13 | Preference: -7.82992533515Expected reward: 11.866419726345484 | Selection probability: 1.2337498052271344e-10 | Preference: -1.99777839484Expected reward: 75.41139657867947 | Selection probability: 1.5933517476231946e-09 | Preference: 0.560588358966Expected reward: -72.44467653824414 | Selection probability: 3.4267025247257986e-13 | Preference: -7.88399339198Expected reward: -43.466561447399 | Selection probability: 1.5933517476231946e-09 | Preference: 0.560588358966Expected reward: -75.99171566420297 | Selection probability: 1.5933517476231946e-09 | Preference: 0.560588358966Expected reward: -82.11920932060593 | Selection probability: 3.120658098513757e-13 | Preference: -7.97754791911Expected reward: 95.00643386364632 | Selection probability: 1.5933517476231946e-09 | Preference: 0.560588358966Expected reward: 31.384022070017835 | Selection probability: 1.2605442916195123e-08 | Preference: 2.62887724114Expected reward: 49.83925652065625 | Selection probability: 0.9999999808967586 | Preference: 20.8180143641
最后一个动作的期望奖励为49.8,老虎机几乎每次都选择它。这是10个选项中的第三好的选择,但它忽略了一个期望奖励为75.4的选项和另一个期望奖励为95.0的选项。
所以,我的疑问是:为什么这个老虎机会错过最优选择?这只是一个例子,当我运行程序时,这种情况相当频繁地发生。是我对老虎机应该做什么的直觉有误,还是我对这个算法的编码有问题?
回答:
问题在于,在你当前的设置下,许多臂(或动作;我使用“臂”是因为这是MAB问题中最常见的术语)甚至一次都没有被选择过。你可以通过打印每个臂被选择的频率来轻易验证这一点。
这是因为你的奖励具有相当高的绝对值。在关于MAB问题的文献中,它们通常假设奖励在[0, 1]或[-1, 1]之间。这并不是绝对必要的(虽然对于一些与算法理论性能相关的证明来说是必要的…但这可能对你目前来说并不重要)。无论如何,你可以采取几种方法来解决这个问题:
1)将偏好列表(H
)初始化为高值,而不是0
。这与书中早期描述的epsilon
-贪婪的乐观初始化有类似的效果,因为它激励算法在早期进行更多的探索。
2)大幅降低学习率alpha
的值。尝试使用0.00001
而不是0.1
。这样做的效果是H
中的偏好值以较小的速率远离0
,因此pi
中的概率也以较小的速率远离初始的1/k
。
3)重新缩放奖励值,使其位于例如[-1, 1]之间(这也需要适当减少奖励分布的标准差,如果你不想使问题变得更复杂的话)。