我一直在尝试实现强化学习书籍中的练习2.5
我根据这个伪代码版本编写了这段代码
class k_arm: def __init__(self, iter, method="incrementally"): # self.iter 占位符 self.iter = iter self.k = 10 self.eps = .1 # 这里是 Q(a) 和 N(a) self.qStar = np.zeros(self.k) self.n = np.zeros(self.k) # 方法仅用于实验不同的函数 self.method = method def pull(self): # 以 (1 - eps) 的概率选择 argmax(Q(A)) 动作 eps = np.random.uniform(0, 1, 1) if eps < self.eps or self.qStar.argmax() == 0: a = np.random.randint(10) else: a = self.qStar.argmax() # R bandit(A) r = np.random.normal(0, 0.01, 1) # N(A) <- N(A) + 1 self.n[a] += 1 # Q(A) <- Q(A) i / (N(A)) * (R - Q(A)) if self.method == "incrementally": self.qStar[a] += (r - self.qStar[a]) / self.n[a] return self.qStar[a]`
iter = 1000rewards = np.zeros(iter)c = k_arm(iter, method="incrementally")for i in range(iter): k = c.pull() rewards[i] = k
我得到的结果是这样的
而我期望的结果是这样的。
我一直在尝试理解我哪里出错了,但没能找到原因。
回答:
你的平均奖励约为0,因为这是正确的估计。你的奖励函数定义为:
# R bandit(A) r = np.random.normal(0, 0.01, 1)
这意味着你的奖励分布的期望值为0,标准差为0.01。书中作者使用了不同的奖励函数。虽然这仍然存在根本性问题,但如果你将代码更改为
# R bandit(A) r = np.random.normal(1.25, 0.01, 1)
你可以获得类似的奖励。给每个匪徒设置不同的奖励函数是有意义的,否则所有动作值都将相同。所以你真正应该做的是从k
个具有不同期望值的不同分布中抽样。否则动作选择将毫无意义。在你的init
函数中添加以下内容:
self.expected_vals = np.random.uniform(0, 2, self.k)
并更改奖励的计算方式,使其依赖于动作:
r = np.random.uniform(self.expected_vals[a], 0.5, 1)
我还将方差增加到0.5,因为0.01在匪徒的上下文中基本上是无意义的方差。如果你的代理工作正常,他的平均奖励应该大约等于np.max(self.expected_vals)