目录

Task 1 Frozen Lake MDP
Policy Iteration
-
Policy Evaluation
固定当前策略π,更新状态价值函数V直至收敛。# 反复迭代直至收敛 while True: value_function_next = np.zeros_like(value_function) for s in range(nS): # 一轮迭代 a = policy[s] prob, nextstate, reward, done = P[s][a][0] # 此prob为π(s,a,s'),而不是π(s,a) value_function_next[s] = prob * (reward + gamma*value_function[nextstate]) if np.max(np.abs(value_function_next - value_function)) < tol: break value_function = value_function_next
-
Policy Improvement
贪心选取使q(s, a)最大的a作为s的策略动作。# 确定性动作 for s in range(nS): q = np.zeros(nA) for a in range(nA): prob, nextstate, reward, done = P[s][a][0] # 此prob为π(s,a,s'),而不是π(s,a) q[a] = prob * (reward + gamma * value_from_policy[nextstate]) new_policy[s] = np.argmax(q)
-
重复策略评估和策略改进,直至策略收敛
while True: value_function = policy_evaluation(P, nS, nA, policy, gamma, tol) new_policy = policy_improvement(P, nS, nA, value_function, None, gamma) if (new_policy == policy).all(): break else: policy = new_policy
-
最终的V值和策略分别如下图:
Value Iteration
迭代更新最优值函数直至收敛,并执行一次策略提取。
while True:
value_function_next = np.zeros_like(value_function)
for s in range(nS):
q = np.zeros(nA)
for a in range(nA):
prob, nextstate, reward, done = P[s][a][0] # 此prob为π(s,a,s'),而不是π(s,a)
q[a] = prob * (reward + gamma * value_function[nextstate])
value_function_next[s] = np.max(q)
if np.max(np.abs(value_function_next - value_function)) < tol:
break
value_function = value_function_next
# 一次策略提取
for s in range(nS):
q = np.zeros(nA)
for a in range(nA):
prob, nextstate, reward, done = P[s][a][0] # 此prob为π(s,a,s'),而不是π(s,a)
q[a] = prob * (reward + gamma * value_function[nextstate])
policy[s] = np.argmax(q)
V值和策略P与策略迭代方法相同。
Task 2 Test Environment
使用动态规划DP自底向上求解,如下图,因为DP是精确算法,所以求解的是最优解。
Task 3 Tabular Q-Learning
agent探索概率epsilon线性递减
assert self.nsteps >= 1
k = (self.eps_end - self.eps_begin) / (self.nsteps - 0)
if t <= self.nsteps:
self.epsilon = self.eps_begin + k * (t - 0)
else:
self.epsilon = self.eps_end
ϵ − g r e e d y \mathbf{\epsilon-greedy} ϵ−greedy Exploration Strategy
if np.random.rand() <= self.epsilon:
return self.env.action_space.sample()
else:
return best_action
Task 4 Maze Example
实现Q Learning和SARSA算法,两个算法很类似,只不过SARSA是on policy,其用于产生训练数据的决策策略和更新Q表的优化策略相同,都是 ϵ − g r e e d y \mathbf{\epsilon-greedy} ϵ−greedy,Q Learning是off policy,其决策策略使用 ϵ − g r e e d y \mathbf{\epsilon-greedy} ϵ−greedy,优化策略使用贪心策略。
1. 观测值说明
agent的观测值(x1, y1, x2, y2),(x1, y1)为agent所处的左上角坐标,(x2, y2)为agent的右下角坐标。将16个左上角坐标映射为0-15,作为状态,也即Q表的行索引,已标记在下图中。坐标系即状态空间如下图所示。由左上角左边换算为Q标行索引的公式为
index = (x1-5)//40 + (y1-5)//40 * 4
2. 动作空间说明
由environment的实现逻辑,在4x4的网格内,0:向上移动一格,1:向下移动一格,2:向右移动一格,3:向左移动一格;当执行动作会超出边界时,则保存在原位置不动。
3. Q Learning实验
部分核心代码如下:
初始化Q表
np.random.seed(1)
obs_dim = 4 * 4 # 观测空间为16
self.q = np.random.rand(obs_dim, len(actions))
选择动作
# epsilon 贪心
if np.random.rand() < self.epsilon:
action = np.random.choice(len(self.actions))
else:
# 由观测坐标换算为状态序号,agent左上角坐标为(x=observation[0], y=observation[1])
# 换算公式为index = (x-5)//40 + (y-5)//40 * 4
x, y = int(observation[0]), int(observation[1]) # 提取observation的左上角坐标
s_idx = (x-5)//40 + (y-5)//40 * 4 # 换算为Q表的行下标
action = np.argmax(self.q[s_idx, :])
return action
更新Q表
x, y = int(s[0]), int(s[1]) # 提取s的左上角坐标
idx_s = (x - 5) // 40 + (y - 5) // 40 * 4 # 换算为Q表的行下标
if self.check_state_exist(s_):
td_target = r + self.gamma * 0 # 终止状态的Q值为0
else:
x_, y_ = int(s_[0]), int(s_[1]) # 提取s_的左上角坐标
idx_s_ = (x_ - 5) // 40 + (y_ - 5) // 40 * 4 # 换算为Q表的行下标
td_target = r + self.gamma * np.max(self.q[idx_s_, :])
self.q[idx_s, a] = self.q[idx_s, a] + self.lr * (td_target - self.q[idx_s, a])
判断终止状态
if state == 'terminal':
return True
else:
return False
ϵ
\mathbf{\epsilon}
ϵ设为0.2,训练500个episodes,Q表如下,结合上图的坐标系、状态空间和动作空间,可以发现已经学习到策略:在状态5,Q(5,1)和Q(5,2)很小,能避免黑块;而在黄色奖励附近,Q(11,3)和Q(14,0)很大,能够到达奖励。可视化实验也显示agent总是能较快到达奖励位置。
训练1000个episodes后的Q表
4. SARSA实验
SARSA与Q Learning类似,只是SARSA更新Q表的优化策略仍是
ϵ
−
g
r
e
e
d
y
\mathbf{\epsilon-greedy}
ϵ−greedy,为on policy算法。
与Q Learning的区别部分如下:
x, y = int(s[0]), int(s[1]) # 提取s的左上角坐标
idx_s = (x - 5) // 40 + (y - 5) // 40 * 4 # 换算为Q表的行下标
if self.check_state_exist(s_):
td_target = r + self.gamma * 0 # 终止状态的Q值为0
else:
x_, y_ = int(s_[0]), int(s_[1]) # 提取s_的左上角坐标
idx_s_ = (x_ - 5) // 40 + (y_ - 5) // 40 * 4 # 换算为Q表的行下标
if np.random.rand() < self.epsilon:
action = np.random.choice(len(self.actions))
td_target = r + self.gamma * (self.q[idx_s_, action])
else:
td_target = r + self.gamma * np.max(self.q[idx_s_, :])
self.q[idx_s, a] = self.q[idx_s, a] + self.lr * (td_target - self.q[idx_s, a])
ϵ
\mathbf{\epsilon}
ϵ仍设为0.2,500个episodes后的Q表如下,实验显示agent已经学到较快到达奖励的策略。
训练1000个episodes后的Q表如下。