提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
个人笔记,恳求纠错,请勿转载
一、Mc.es是什么?
MC Basic exploring starts 是什么?先给出伪代码
1.use the first-visit? 就比如s,a - - s1,a1- -s2,a2- -s,a-----
这个探索过程包含了两步s,a,我们在执行到第二次s,a的时候停止探索。这样就保证了每次探索只会有一次s,a。这样不仅节省了计算时间,也节约了探索时间。但在实际过程中仍然需要我们遍历完所有的s,a。
2.该算法每次探索都会更新policy,相较于MC Basic,它不需要等所有数据都得到了才policy improvement,提升了效率。
3.所以MC-es 实际上就是将繁冗的MC Basic 切片,并提升效率的算法
二、代码
import numpy as np
import matplotlib.pyplot as plt
from gridWorldGame import standard_grid, negative_grid,print_values, print_policy
SMALL_ENOUGH = 1e-3
GAMMA = 0.9
ALL_POSSIBLE_ACTIONS = ('U', 'D', 'L', 'R')
def play_game(grid, policy):
start_states = list(grid.actions.keys()) #start_States = policy
start_idx = np.random.choice(len(start_states)) # random policy
grid.set_state(start_states[start_idx])
s = grid.current_state() # policy's state
a = np.random.choice(ALL_POSSIBLE_ACTIONS)
states_actions_rewards = [(s, a, 0)] # 存放states_actions_rewards
seen_states = set() # 去过的地方不再去
seen_states.add(grid.current_state())
num_steps = 0 # step
while True: # 循环,如果来到走过的地方,就停止循环;或者走到终点
r = grid.move(a) # 走a
num_steps += 1 # 步数加一
s = grid.current_state()
if s in seen_states:
reward = -10. / num_steps # 步数越少,reward负得越多
states_actions_rewards.append((s, None, reward)) # 因为停了,所以是none
break
elif grid.game_over(): # 走到最后了
states_actions_rewards.append((s, None, r))
break
else: #
a = policy[s]
states_actions_rewards.append((s, a, r)) # s和a是current_state的量,r走到这得到的reward
seen_states.add(s)
G = 0
states_actions_returns = [] # 记录returns
first = True
for s, a, r in reversed(states_actions_rewards):
if first: # 就是不要(s, None, r)或者(s, None, reward)
first = False
else:
states_actions_returns.append((s, a, G))
G = r + GAMMA*G
states_actions_returns.reverse()
return states_actions_returns
def max_dict(d):
max_key = None
max_val = float('-inf')
for k, v in d.items():
if v > max_val:
max_val = v
max_key = k
return max_key, max_val
grid = negative_grid(step_cost = -0.9)
policy = {}
for s in grid.actions.keys():
policy[s] = np.random.choice(ALL_POSSIBLE_ACTIONS)
Q = {}
returns = {}
states = grid.all_states()
for s in states: # 将各个s对应的四种动作的value赋值为0
if s in grid.actions:
Q[s] = {}
for a in ALL_POSSIBLE_ACTIONS:
Q[s][a] = 0 #Q中键值s对应多个a,这是一键多值的表示方法
returns[(s, a)] = [] #创建了一个键(s,a)
else:
pass # 什么都不执行
deltas = []
for t in range(2000):
biggest_change = 0
states_actions_returns = play_game(grid, policy)
seen_state_action_pairs = set() #创建元组,存放做过的s, a
for s, a, G in states_actions_returns:
sa = (s, a)
if sa not in seen_state_action_pairs:
old_q = Q[s][a]
returns[sa].append(G)
Q[s][a] = np.mean(returns[sa])
biggest_change = max(biggest_change, np.abs(old_q - Q[s][a]))
seen_state_action_pairs.add(sa)
deltas.append(biggest_change)
for s in policy.keys():
policy[s] = max_dict(Q[s])[0] # 每一个s都要取最大的policy
plt.plot(deltas)
plt.show()
print("final policy")
print_policy(policy, grid)
V = {}
for s, Qs in Q.items():
V[s] = max_dict(Q[s])[1]
print("final values:")
print_values(V, grid)
这次的代码我花了很长的时间去理解,具体有这样几个问题:
1.play_game()的结束方式,增加了一个遇到重复s,a跳出这样一个条件,这就是上面说的切片,绝不允许一个episode有两个同样的s,a
2.Q这样一个变量实际上本身是一个字典有key和value,那么Q[0]就是指这个字典key为0时的value了。但这个字典在Q[0]又定义Q[0]={}就是将0处的值又变成一个字典。
3.2000次循环中,其实每次只对单个s,a产生一个return。2000次循环也就是2000个return,但它每次循环都会更新policy,所以说前几次的policy一定是不准的。
三.结果展示
实际上还是有缺陷的,比如(2,3)这个位置。因为除了policy为left时会得到正常的return。其它三个方向都会返回-1,这就导致数据足够多时,state_value会无限趋近于-1,最终导致如上结果:错误的policy。
四.总结
MC-es算法总体来说对比MC Basic算法效率提高了,但仍然有改进方法。
摘录于:https://github.com/rookiexxj/Reinforcement_learning_tutorial_with_demo/blob/master/monte_carlo_es_demo.ipynb
https://www.bilibili.com/video/BV1sd4y167NS?p=21&vd_source=35775f5151031f11ee2a799855c8e368