- 簡介
- 迷你项目:OpenAI Gym-CliffWalkingEnv
- TD 預測:TD(0)
- 實現 - TD(0)
- 迷你项目 part0,1
- TD 預測:動作值
- TD 控制:Sarsa(0)
- 實現 - Sarsa(0)
- 迷你项目 part2
- TD 控制:Sarsamax
- 實現 - Sarsamax
- 迷你项目 part3
- TD 控制:預期Sarsa
- 實現 - 預期Sarsa
- 迷你项目 part4
- 分析性能
- 總結
- 蒙特卡洛方法只適用於階段性任務,在每個階段結束後,更新策略。時間差分方法可以用在階段性也可以用在連續性任務。
- 例子: 無人車需要在每個路口能夠判斷自己是否會撞車,並且在必要時修改策略,避免發生車禍。在蒙特卡洛方法下,若想要學習某個規律,則必須每次都要撞車,才能結束這階段任務。
- 時間差分方法,將在每個時間步都在修改預測,而不是等互動結束才更新。
- GitHub 文件
- 一个 4x12 的矩阵(使用 Numpy 矩阵索引):
- 左下角的 [3, 0] 是起点
- 右下角的 [3, 11] 是目标
- 底部中心的 [3, 1..10] 是悬崖
- 每个时间步都会获得 -1 奖励,跌入悬崖会获得 -100 奖励并重置为起点。当智能体抵达目标时阶段结束。
-
首先,還是先討論預測問題(prediction problem)。
-
回顧: 蒙特卡洛方法是如何進行預測
- agent以階段性的方式跟env進行互動。
- 如果是first-visit,則計算相對應的回報,並用來更新動作值。
- 需要注意,我們不能再每個階段之間更改策略。
- 然後,經歷很多很多的階段,得到一個很完美的動作值函數的估計結果,來解決預測問題。
- 接下來的重點: 我們要透過修改更新步驟這個函數來達到即更新的目的。
- 不是像蒙特卡洛方法每個階段更新一次。
- 重點: 修改流程
- Gt: agent遵守某個policy下,在狀態s下可能會得到的預期回報。
- 將Gt根據貝爾曼方程式進行改寫。
- 現在,不再針對取樣回報取平均值
- 而是 -- 下個時間步的即時獎勵 + 下個時間步的折扣率 * 下個時間步的狀態值
- 透過這樣的修改,可以讓我們在每個時間步更新狀態值。
- 現在更新函數,就可以利用當下這個時間步做即時的更新。
- 不用再等階段結束才更新。
- 重新改寫一下更新函數
- 當alpha = 1, 表示新的估計值就是TD目標。
- 當alpha = 0, 則完全忽略TD目標,保留舊的估計值,這樣agent就無法學到規律了。
- 當alpha越低,表示在更新時,對TD目標的信任就越低,比較依賴目前狀態的現有估值。
- One-Step TD for 連續性任務
- 每個時間步之後都更新值函數。
- One-Step TD for 階段性任務
- 多個檢查是否當下這個state是否為terminal狀態。
from collections import defaultdict, deque
import sys
def td_prediction(env, num_episodes, policy, alpha, gamma=1.0):
# initialize empty dictionaries of floats
V = defaultdict(float)
# loop over episodes
for i_episode in range(1, num_episodes+1):
# episode準備開始
state = env.reset()
# TD for 階段性任務
while True:
# 根據policy選擇對應的action
action = policy[state]
# 根據action得到reward跟下一個state
next_state, reward, done, info = env.step(action)
# 執行 TD 的更新
V[state] = V[state] + (alpha * (reward + (gamma * V[next_state]) - V[state]))
# 更新state
state = next_state
# 對於階段性任務,要多檢查目前state是否為terminal狀態
# 連續性任務就不需要這一步
if done:
break
return V
- 在上個階段,我們學會如何即時更新狀態函數的方法,
- agent 會在S1去更新S0狀態,在St去更新St-1的狀態。
- 接下來就是要如何即時更新動作函數。
- 類似的概念,一樣在St+1, At+1去更新St, At的狀態。
- 在上面已經解決預測問題,現在要來處理控制問題,如何及時去更新策略。
- 在每個時間步使用一個針對當前動作估值,利用Epsilon greedy policy來選擇一個動作。
# 先準備一些helper function
# action-value function的更新
# 利用Q+1來更新Q
def update_Q(Qsa, Qsa_next, reward, alpha, gamma):
return Qsa + (alpha * (reward + (gamma * Qsa_next) - Qsa))
# 根據epsilon-greedy policy來決定每個state中每個action的機率
# 有一定的機率會非最高的動作值
def epsilon_greedy_probs(env, Q_s, i_episode, eps=None):
# 隨著episode執行越多次,epsilon就越小,就越greedy
epsilon = 1.0 / i_episode
if eps is not None:
epsilon = eps
# 利用epsilon控制greedy程度, epsilon越小,越greedy
policy_s = np.ones(env.nA) * epsilon / env.nA # 讓每個狀態下的每個action都有機會被執行到
policy_s[np.argmax(Q_s)] = 1 - epsilon + (epsilon / env.nA) # 進行greedy
return policy_s
def sarsa(env, num_episodes, alpha, gamma=1.0):
# initialize action-value function (empty dictionary of arrays)
Q = defaultdict(lambda: np.zeros(env.nA))
# loop over episodes
for i_episode in range(1, num_episodes+1):
# 分數初始化
score = 0
# 狀態初始化 -- (S0)
state = env.reset()
# 根據epsilon-greedy獲得每個action執行的機率
policy_s = epsilon_greedy_probs(env, Q[state], i_episode)
# 根據機率來隨機挑選動作 -- (A0)
action = np.random.choice(np.arange(env.nA), p=policy_s)
# 限制每次episode最多只能進行300步
for t_step in np.arange(300):
# 根據action得到reward跟下一個state
next_state, reward, done, info = env.step(action)
# 將reward加入score -- (R1)
score += reward
if not done:
# 再次根據epsilon-greedy獲得每個action執行的機率 -- (S1)
policy_s = epsilon_greedy_probs(env, Q[next_state], i_episode)
# 再次根據機率來隨機挑選動作 -- (A1)
next_action = np.random.choice(np.arange(env.nA), p=policy_s)
# 進行action function的更新,利用TD來更新Q
Q[state][action] = update_Q(Q[state][action], Q[next_state][next_action],
reward, alpha, gamma)
# 更新狀態跟動作
state = next_state
action = next_action
if done:
# 進行action function的更新,利用TD來更新Q
Q[state][action] = update_Q(Q[state][action], 0, reward, alpha, gamma)
break
return Q
- 回顧Sarsa(0)
- 初始化所有狀態下動作值函數。
- 利用Epsilon greedy policy,決定一個policy。
- 利用這個policy來產生到A1。
- A1出現後,再次更新動作值函數跟策略。
- Sarsamax (Q-Learning)
- 跟Sarsa(0)不同點: 在A1之前就更新策略
- 直接找出最大化當下狀態的動作值的動作
- Sarsamax, Sarsa(0)差異
def q_learning(env, num_episodes, alpha, gamma=1.0):
# initialize empty dictionary of arrays
Q = defaultdict(lambda: np.zeros(env.nA))
tmp_scores = deque(maxlen=plot_every)
# loop over episodes
for i_episode in range(1, num_episodes+1):
# 分數初始化
score = 0
# 狀態初始化 -- (S0)
state = env.reset()
while True:
# 根據epsilon-greedy獲得每個action執行的機率
policy_s = epsilon_greedy_probs(env, Q[state], i_episode)
# 根據機率來隨機挑選動作 -- (A0)
action = np.random.choice(np.arange(env.nA), p=policy_s)
# 根據A0獲得 R1, S1
next_state, reward, done, info = env.step(action)
# 將reward加入score -- (R1)
score += reward
# 跟Sarsa(0)不同點 -- 不利用用next_action(A1)協助更新
Q[state][action] = update_Q(Q[state][action], np.max(Q[next_state]), \
reward, alpha, gamma)
# 更新狀態
state = next_state
if done:
# append score
tmp_scores.append(score)
break
return Q
-
根據當下狀態的每個動作的機率,進行所有不同動作值相加
- Sarsamax: 考慮最大化的動作。
- Expected Sarsa: 考慮所有動作。
def expected_sarsa(env, num_episodes, alpha, gamma=1.0):
# initialize empty dictionary of arrays
Q = defaultdict(lambda: np.zeros(env.nA))
# initialize performance monitor
scores = deque(maxlen=num_episodes)
# loop over episodes
for i_episode in range(1, num_episodes+1):
# 分數初始化
score = 0
# 狀態初始化 -- (S0)
state = env.reset()
# 不同點 -- 在greedy方式設置常數0.005
policy_s = epsilon_greedy_probs(env, Q[state], i_episode, 0.005)
while True:
# 根據機率來隨機挑選動作 -- (A0)
action = np.random.choice(np.arange(env.nA), p=policy_s)
# 根據A0獲得 R1, S1
next_state, reward, done, info = env.step(action)
# 將reward加入score -- (R1)
score += reward
# 不同點 -- 先取得S1所有action的機率
policy_s = epsilon_greedy_probs(env, Q[next_state], i_episode, 0.005)
# 跟SarsaMax不同點 -- 不是取max, 而是利用policy_s的內積來進行更新
Q[state][action] = update_Q(Q[state][action], np.dot(Q[next_state], policy_s), \
reward, alpha, gamma)
# 更新狀態
state = next_state
if done:
# append score
tmp_scores.append(score)
break
return Q
- 我们讨论过的所有 TD 控制算法(Sarsa、Sarsamax、预期 Sarsa)都会收敛于最优动作值函数 q∗(并生成最优策略 π∗):(1) ϵ 的值根据 GLIE 条件逐渐降低,以及 (2) 步长参数 α 足够小。
这些算法之间的区别总结如下:
- Sarsa 和预期 Sarsa 都是异同策略 TD 控制算法。在这种情况下,我们会根据要评估和改进的相同(
ϵ 贪婪策略)策略选择动作。
- 先進行下一步動作後,才更新策略。
- Sarsamax 是离线策略方法,我们会评估和改进(ϵ 贪婪)策略,并根据另一个策略选择动作。
- 先更新策略,才進行下一步動作。
- 既定策略 TD 控制方法(例如预期 Sarsa 和 Sarsa)的在线效果比新策略 TD 控制方法(例如 Sarsamax)的要好。
- 预期 Sarsa 通常效果比 Sarsa 的要好。
- 簡單來說,效果由好到壞: 预期 Sarsa > Sarsa > Sarsamax