我在使用Python 2.7.11开发一个Agent
类,该类使用马尔可夫决策过程(MDP)在GridWorld
中搜索最优策略π。我正在实现一个基本的价值迭代,用于对所有GridWorld
状态进行100次迭代,使用以下贝尔曼方程:
- T(s,a,s’)是从当前状态s通过采取行动a成功过渡到后续状态s’的概率函数。
- R(s,a,s’)是从s过渡到s’的奖励。
- γ(gamma)是折扣因子,其中0 ≤ γ ≤ 1。
- Vk(s’)是在达到s’后重复计算的递归调用。
- Vk+1(s)表示经过足够的k次迭代后,Vk迭代值将收敛并与Vk+1等价。
这个方程是从取Q值函数的最大值中得出的,这是我在程序中使用的:
在构建我的Agent
时,会传入一个MDP,这是一个包含以下方法的抽象类:
# 返回GridWorld中的所有状态def getStates()# 返回给定当前状态下代理可以采取的所有合法行动def getPossibleActions(state)# 返回从当前状态通过给定行动可以过渡到的所有可能的后续状态,以及采取该行动达到每个状态的概率def getTransitionStatesAndProbs(state, action)# 返回从当前状态到后续状态的奖励def getReward(state, action, nextState)
我的Agent
还被传入一个折扣因子和迭代次数。我还使用了一个字典
来跟踪我的值。以下是我的代码:
class IterationAgent: def __init__(self, mdp, discount = 0.9, iterations = 100): self.mdp = mdp self.discount = discount self.iterations = iterations self.values = util.Counter() # Counter是一个默认值为0的字典 for transition in range(0, self.iterations, 1): states = self.mdp.getStates() valuesCopy = self.values.copy() for state in states: legalMoves = self.mdp.getPossibleActions(state) convergedValue = 0 for move in legalMoves: value = self.computeQValueFromValues(state, move) if convergedValue <= value or convergedValue == 0: convergedValue = value valuesCopy.update({state: convergedValue}) self.values = valuesCopy def computeQValueFromValues(self, state, action): successors = self.mdp.getTransitionStatesAndProbs(state, action) reward = self.mdp.getReward(state, action, successors) qValue = 0 for successor, probability in successors: # Q值方程:Q*(a,s) = T(s,a,s')[R(s,a,s') + gamma(V*(s'))] qValue += probability * (reward + (self.discount * self.values[successor])) return qValue
这个实现是正确的,但我不知道为什么需要valuesCopy
来成功更新我的self.values
字典。我尝试了以下方法来省略拷贝,但它不起作用,因为它返回了略有错误的值:
for i in range(0, self.iterations, 1): states = self.mdp.getStates() for state in states: legalMoves = self.mdp.getPossibleActions(state) convergedValue = 0 for move in legalMoves: value = self.computeQValueFromValues(state, move) if convergedValue <= value or convergedValue == 0: convergedValue = value self.values.update({state: convergedValue})
我的问题是,为什么在每次迭代中valuesCopy = self.values.copy()
都会对字典进行拷贝的情况下,还需要包含self.values
字典的拷贝来正确更新我的值?难道在原始字典中更新值不会产生相同的更新结果吗?
回答:
是否使用拷贝在算法上是有区别的:
# 你在这里更新你的拷贝,所以原始的将保持不变,这与没有拷贝的情况不同valuesCopy.update({state: convergedValue})# 如果你有拷贝,你将在这里使用存储在self.value中的旧值,而不是更新后的值qValue += probability * (reward + (self.discount * self.values[successor]))