在很多实际问题中,我们无法得到游戏的全貌,也就是说,状态转移矩阵无法获知,这被称为“无模型”问题。
Bellman公式,可以通过不断迭代得到状态-行动值函数
而在无模型问题中,状态转移概率将无法知晓,于是用最初的累积回报求得
看到等号右边的期望,我们很自然地联想到了蒙特卡罗法,它是一种通过随机采样估计期望值的方法,全过程总结如下:
(1)让Agent和环境交互后得到交互序列
(2)通过序列计算出每一时刻的价值
(3)将这些价值累积到值函数中进行更新
(4)根据更新的值函数更新策略
代码如下:
# 蒙特卡罗方法
class MonteCarlo(object):
def __init__(self, epsilon=0.0):
self.epsilon = epsilon
def monte_carlo_eval(self, agent, env):
state = env.reset()
episode = []
# 使用当前策略,产生序列
while True:
ac = agent.play(state, self.epsilon)
next_state, reward, terminate, _ = env.step(ac)
episode.append((state, ac, reward))
state = next_state
if terminate:
break
value = []
return_val = 0.0
# 计算回报 q = sum(r^k*R)
for item in reversed(episode):
return_val = return_val * agent.gamma + item[2]
value.append((item[0], item[1], return_val))
#
for item in reversed(value):
agent.value_n[item[0]][item[1]] += 1 # 计数
# 求期望,qt(N-1) = qt(N-1) + 1/N (q^t(N) - qt(N-1))
agent.value_q[item[0]][item[1]] += ( (item[2]-agent.value_q[item[0]][item[1]]) /
agent.value_n[item[0]][item[1]])
def policy_improve(self, agent):
new_policy = np.zeros_like(agent.pi)
for i in range(1, agent.s_len):
new_policy[i] = np.argmax(agent.value_q[i,:]) # 去最大q(a|s)作为下一个策略
if np.all(np.equal(new_policy, agent.pi)):
return False
else:
agent.pi = new_policy
return True
def monte_carlo_opt(self, agent, env):
for i in range(10):
# 试玩100次
for j in range(100):
self.monte_carlo_eval(agent, env)
self.policy_improve(agent)
from contextlib import contextmanager
import time
@contextmanager
def timer(name):
start = time.time()
yield
end = time.time()
print('{} COST:{}'.format(name, end - start))
# 没有模型
class ModelFreeAgent(object):
def __init__(self, env):
self.s_len = env.observation_space.n
self.a_len = env.action_space.n
self.pi = np.array([0 for s in range(0, self.s_len)]) # 转移矩阵
self.value_q = np.zeros((self.s_len, self.a_len))
self.value_n = np.zeros((self.s_len, self.a_len))
self.gamma = 0.8
def play(self, state, epsilon = 0):
if np.random.rand() < epsilon:
return np.random.randint(self.a_len)
else:
return self.pi[state]
# 测试
def monte_carlo_demo():
np.random.seed(101)
env = SnakeEnv(10, [3,6])
agent = ModelFreeAgent(env)
mc = MonteCarlo(0.5)
with timer('Timer Monte Carlo Iter'):
mc.monte_carlo_opt(agent, env)
print('return_pi={}'.format(eval_game(env,agent)))
print(agent.pi)
monte_carlo_demo()
可以看出,蒙特卡罗法的效果比策略迭代差一些,由于状态转移矩阵未知,因此存在一些差距是可以理解的。
为了保证所有的状态和行动组合全部被Agent经历过,而且经历次数足够多,使用了epsilon-greedy算法,实际上该算法解决了“探索和利用”问题。所谓的探索是指不拘泥于当前的表现,选择一些不同于当前策略的行动;利用就是持续使用当前的最优策略,尽可能地获得更多的回报。
虽然它对期望值的估计是无偏的,但是方差较高,为此提出时序差分法(Temporal Difference)