1 Q Learning算法
Q更新公式:
∈-greedy策略
在Q Learning的更新過程中,每一步都要根據當前的state以及Q函數確定一個合適的行動action。這裏有一個如何平衡“經驗”和“探索”的問題。如果完全按照經驗行動,即每次都在Q(state, :)中選擇對應值最大的action,那麼很有可能一直侷限在已有經驗中,難以發現更具價值的新的行爲。但如果智能體只專注於探索新的行爲,即完全隨機地行動,又可能因爲大多數行動都沒有價值,導致學習Q函數的速度很慢。
一種比較簡單的平衡“經驗”和“探索”的方法是採用∈-greedy策略選擇合適的行動。事先設置一個較小的∈值(如∈=0.1),智能體有1-∈的概率根據學習到的Q函數(已有經驗)行動,剩下∈的概率智能體會隨機行動,用於探索新的經驗。例如,∈=0.1時,在90%的情況下,智能體直接選擇使得Q(state, action)最大的action,剩下10%的情況,隨機選擇一個action。
2 SARSA(state-action-reward-state-action)
off-policy和on-policy
強化學習中的方法可以分爲off-policy和on-policy兩類。Q Learning算法是一個經典的off-policy方法,而SARSA算法則是on-policy方法。那麼,如何理解這裏的off-policy和on-policy呢?
在Q Learning中,Q函數的更新和Q[new_state, :].max()有關。在Q[new_state, :]中選出使得Q函數最大的動作,以此來更新Q函數。設這個動作爲max_action。注意,智能體實際有可能並不會執行max_action。因爲在下一個過程中是根據epsilon-greedy方法來選擇策略的,有可能選擇max_action,也有可能並不會選到max_action。而SARSA算法則不同,它用Q[new_state, new_action]結合獎勵等信息更新Q函數。之後,在下一次循環時,智能體必然會執行new_action。
說Q Learning是一種off-policy算法,是指它在更新Q函數時使用的動作(max_action)可能並不會被智能體用到。又稱SARSA是一種on-policy方法,是指它在更新Q函數時使用的動作(new_action)一定會被智能體所採用。這也是on-policy方法和off-policy方法的主要區別。
3 Q Learning和SARSA對比
相比Q Learning算法,SARSA算法更“膽小”。Q Learning算法會使用Q[new_state, :].max()來更新Q值,換句話說,它考慮的是新狀態下可以獲得的最大獎勵,而不去考慮新狀態會帶來的風險。因此,Q Learning算法會更加的激進。相比之下,SARSA算法只是使用Q[new_state, new_action]來更新Q值。在此處的迷宮問題中,SARSA算法會考慮到接近陷阱可能帶來的負收益,因此更傾向於待在原地不動,從而更加難以找到“寶藏”.
4 python 實現
q-learning
from __future__ import print_function
import numpy as np
import time
from env import Env
EPSILON = 0.1
ALPHA = 0.1
GAMMA = 0.9
MAX_STEP = 30
np.random.seed(0)
def epsilon_greedy(Q, state):
if (np.random.uniform() > 1 - EPSILON) or ((Q[state, :] == 0).all()):
action = np.random.randint(0, 4) # 0~3
else:
action = Q[state, :].argmax()
return action
e = Env()
Q = np.zeros((e.state_num, 4))
for i in range(200):
e = Env()
while (e.is_end is False) and (e.step < MAX_STEP):
action = epsilon_greedy(Q, e.present_state)
state = e.present_state
reward = e.interact(action)
new_state = e.present_state
Q[state, action] = (1 - ALPHA) * Q[state, action] + \
ALPHA * (reward + GAMMA * Q[new_state, :].max())
e.print_map()
time.sleep(0.1)
print('Episode:', i, 'Total Step:', e.step, 'Total Reward:', e.total_reward)
time.sleep(2)
SARSA
from __future__ import print_function
import numpy as np
import time
from env import Env
EPSILON = 0.1
ALPHA = 0.1
GAMMA = 0.9
MAX_STEP = 50
np.random.seed(1)
def epsilon_greedy(Q, state):
if (np.random.uniform() > 1 - EPSILON) or ((Q[state, :] == 0).all()):
action = np.random.randint(0, 4) # 0~3
else:
action = Q[state, :].argmax()
return action
e = Env()
Q = np.zeros((e.state_num, 4))
for i in range(200):
e = Env()
action = epsilon_greedy(Q, e.present_state)
while (e.is_end is False) and (e.step < MAX_STEP):
state = e.present_state
reward = e.interact(action)
new_state = e.present_state
new_action = epsilon_greedy(Q, e.present_state)
Q[state, action] = (1 - ALPHA) * Q[state, action] + \
ALPHA * (reward + GAMMA * Q[new_state, new_action])
action = new_action
e.print_map()
time.sleep(0.1)
print('Episode:', i, 'Total Step:', e.step, 'Total Reward:', e.total_reward)
time.sleep(2)