這方面的資料比較零散,學起來各種碰壁,碰到各種問題,這里就做下學習記錄。
參考資料:
非常感謝莫煩老師的教程
http://mnemstudio.org/path-finding-q-learning-tutorial.htm
http://www.cnblogs.com/dragonir/p/6224313.html
這篇文章也是用非常簡單的說明將 Q-Learning 的過程給講解清楚了
http://www.cnblogs.com/jinxulin/tag/%E5%A2%9E%E5%BC%BA%E5%AD%A6%E4%B9%A0/
還有感謝這位園友,將增強學習的原理講解的非常清晰
這里還是先以上面教程中的例子來實現 Q-Learning。
目錄:
Deep Q-Network 學習筆記(一)—— Q-Learning
Deep Q-Network 學習筆記(二)—— Q-Learning與神經網絡結合使用
一、思路

圖 1.1
這里,先自己對那個例子的理解總結一下。
要解決的問題是:如上圖 1.1 中有 5 個房間,分別被標記成 0-4,房間外可以看成是一個大的房間,被標記成 5,現在智能程序 Agent 被隨機丟在 0-4 號 5 個房間中的任意 1 個,目標是讓它尋找到離開房間的路(即:到達 5 號房間)。
圖片描述如下:

圖 1.2
給可以直接移動到 5 號房間的動作獎勵 100 分,即:圖1.2中,4 到 5 、 1 到 5 和 5 到 5 的紅線。
在其它幾個可移動的房間中移動的動作獎勵 0 分。
如下圖:

圖 1.3
假設 Agent 當前的位置是在 2 號房間,這里就將 Agent 所在的位置做為“狀態”,也就是 Agent 當前的狀態是 2,當前 Agent 只能移動到 3 號房間,當它移動到 3 號房間的時候,狀態就變為了 3,此時得到的獎勵是 0 分。
而 Agent 根據箭頭的移動則是一個“行為”。
根據狀態與行為得到的獎勵可以組成以下矩陣。

圖 1.4
同時,可以使用一個 Q 矩陣,來表示 Agent 學習到的知識,在圖 1.4 中,“-1”表示不可移動的位置,比如從 2 號房間移動到 1 號房間,由於根本就沒有門,所以沒辦法過去。

圖 1.5
該 Q 矩陣就表示 Agent 在各種狀態下,做了某種行為后自己給打的分,也就是將經驗數據化,由於 Agent 還沒有行動過,所以這里全是 0。
在 Q-Learning 算法中,計算經驗得分的公式如下:
Q(state, action) = Q(state, action) + α(R(state, action) + Gamma * Max[Q(next state, all actions)] - Q(state, action))
當 α 的值是 1 時,公式如下:
Q(state, action) = R(state, action) + Gamma * Max[Q(next state, all actions)]
state: 表示 Agent 當前狀態。
action: 表示 Agent 在當前狀態下要做的行為。
next state: 表示 Agent 在 state 狀態下執行了 action 行為后達到的新的狀態。
Q(state, action): 表示 Agent 在 state 狀態下執行了 action 行為后學習到的經驗,也就是經驗分數。
R(state, action): 表示 Agent 在 state 狀態下做 action 動作后得到的即時獎勵分數。
Max[Q(next state, all actions)]: 表示 Agent 在 next state 狀態下,自我的經驗中,最有價值的行為的經驗分數。
Gamma: ,γ,表示折損率,也就是未來的經驗對當前狀態執行 action 的重要程度。
二、算法流程
Agent 通過經驗去學習。Agent將會從一個狀態到另一個狀態這樣去探索,直到它到達目標狀態。我們稱每一次這樣的探索為一個場景(episode)。
每個場景就是 Agent 從起始狀態到達目標狀態的過程。每次 Agent 到達了目標狀態,程序就會進入到下一個場景中。
1. 初始化 Q 矩陣,並將初始值設置成 0。
2. 設置好參數 γ 和得分矩陣 R。
3. 循環遍歷場景(episode):
(1)隨機初始化一個狀態 s。
(2)如果未達到目標狀態,則循環執行以下幾步:
① 在當前狀態 s 下,隨機選擇一個行為 a。
② 執行行為 a 得到下一個狀態 s`。
③ 使用 Q(state, action) = R(state, action) + Gamma * Max[Q(next state, all actions)] 公式計算 Q(state, action) 。
④ 將當前狀態 s 更新為 s`。
設當前狀態 s 是 1, γ =0.8和得分矩陣 R,並初始化 Q 矩陣:


由於在 1 號房間可以走到 3 號房間和 5 號房間,現在隨機選一個,選到了 5 號房間。
現在根據公式來計算,Agent 從 1 號房間走到 5 號房間時得到的經驗分數 Q(1, 5) :
1.當 Agent 從 1 號房間移動到 5 號房間時,得到了獎勵分數 100(即:R(1, 5) = 100)。
2.當 Agent 移動到 5 號房間后,它可以執行的動作有 3 個:移動到 1 號房間(0 分)、移動到 4 號房間(0 分)和移動到 5 號房間(0 分)。注意,這里計算的是經驗分數,也就是 Q 矩陣,不是 R 矩陣!
所以,Q(1, 5) = 100 + 0.8 * Max[Q(5, 1), Q(5, 4), Q(5, 5)] = 100 + 0.8 * Max{0, 0, 0} = 100
在次迭代進入下一個episode:
隨機選擇一個初始狀態,這里設 s = 3,由於 3 號房間可以走到 1 號房間、 2 號房間和 4 號房間,現在隨機選一個,選到了 1 號房間。
步驟同上得:Q(3, 1) = 0 + 0.8 * Max[Q(1, 3), Q(1, 5)] = 0 + 0.8 * Max{0, 100} = 0 + 0.8 * 100 = 80
即:

三、程序實現
先引入 numpy:
import numpy as np
初始化:
# 動作數。 ACTIONS = 6 # 探索次數。 episode = 100 # 目標狀態,即:移動到 5 號房間。 target_state = 5 # γ,折損率,取值是 0 到 1 之間。 gamma = 0.8 # 經驗矩陣。 q = np.zeros((6, 6)) def create_r(): r = np.array([[-1, -1, -1, -1, 0, -1], [-1, -1, -1, 0, -1, 100.0], [-1, -1, -1, 0, -1, -1], [-1, 0, 0, -1, 0, -1], [0, -1, -1, 1, -1, 100], [-1, 0, -1, -1, 0, 100], ]) return r
執行代碼:
特別注意紅色字體部分,當程序隨機到不可移動的位置的時候,直接給於死亡扣分,因為這不是一個正常的操作,比如 從 4 號房間移動到 1 號房間,但這兩個房間根本沒有門可以直接到。
至於為什么不使用公式來更新,是因為,如果 Q(4, 5)和Q(1, 5)=100分,
當隨機到(4, 1)時,Q(4, 1)的經驗值不但沒有減少,反而當成了一個可移動的房間計算,得到 79 分,即:Q(4, 1) = 79,
當隨機到(2, 1)的次數要比(4, 5)多時,就會出現Q(4, 1)的分數要比Q(4, 5)高的情況,這個時候,MaxQ 選擇到的就一直是錯誤的選擇。
if __name__ == '__main__': r = create_r() print("狀態與動作的得分矩陣:") print(r) # 搜索次數。 for index in range(episode): # Agent 的初始位置的狀態。 start_room = np.random.randint(0, 5) # 當前狀態。 current_state = start_room while current_state != target_state: # 當前狀態中的隨機選取下一個可執行的動作。 current_action = np.random.randint(0, ACTIONS) # 執行該動作后的得分。 current_action_point = r[current_state][current_action] if current_action_point < 0: q[current_state][current_action] = current_action_point else: # 得到下一個狀態。 next_state = current_action # 獲得下一個狀態中,在自我經驗中,也就是 Q 矩陣的最有價值的動作的經驗得分。 next_state_max_q = q[next_state].max() # 當前動作的經驗總得分 = 當前動作得分 + γ X 執行該動作后的下一個狀態的最大的經驗得分 # 即:積累經驗 = 動作執行后的即時獎勵 + 下一狀態根據現有學習經驗中最有價值的選擇 X 折扣率 q[current_state][current_action] = current_action_point + gamma * next_state_max_q current_state = next_state print("經驗矩陣:") print(q) start_room = np.random.randint(0, 5) current_state = start_room step = 0 while current_state != target_state: next_state = np.argmax(q[current_state]) print("Agent 由", current_state, "號房間移動到了", next_state, "號房間") current_state = next_state step += 1 print("Agent 在", start_room, "號房間開始移動了", step, "步到達了目標房間 5")
下面是運行結果圖:

完整代碼:
import numpy as np # 動作數。 ACTIONS = 6 # 探索次數。 episode = 100 # 目標狀態,即:移動到 5 號房間。 target_state = 5 # γ,折損率,取值是 0 到 1 之間。 gamma = 0.8 # 經驗矩陣。 q = np.zeros((6, 6)) def create_r(): r = np.array([[-1, -1, -1, -1, 0, -1], [-1, -1, -1, 0, -1, 100.0], [-1, -1, -1, 0, -1, -1], [-1, 0, 0, -1, 0, -1], [0, -1, -1, 1, -1, 100], [-1, 0, -1, -1, 0, 100], ]) return r def get_next_action(): # # 獲得當前可執行的動作集合。 # actions = np.where(r[current_state] >= 0)[0] # # # 獲得可執行的動作數。 # action_count = actions.shape[0] # # # 隨機選取一個可執行的動作。 # next_action = np.random.randint(0, action_count) # # # 執行動作,獲得下一個狀態。 # next_state = actions[next_action] next_action = np.random.randint(0, ACTIONS) return next_action if __name__ == '__main__': r = create_r() print("狀態與動作的得分矩陣:") print(r) # 搜索次數。 for index in range(episode): # Agent 的初始位置的狀態。 start_room = np.random.randint(0, 5) # 當前狀態。 current_state = start_room while current_state != target_state: # 當前狀態中的隨機選取下一個可執行的動作。 current_action = get_next_action() # 執行該動作后的得分。 current_action_point = r[current_state][current_action] if current_action_point < 0: q[current_state][current_action] = current_action_point else: # 得到下一個狀態。 next_state = current_action # 獲得下一個狀態中,在自我經驗中,也就是 Q 矩陣的最有價值的動作的經驗得分。 next_state_max_q = q[next_state].max() # 當前動作的經驗總得分 = 當前動作得分 + γ X 執行該動作后的下一個狀態的最大的經驗得分 # 即:積累經驗 = 動作執行后的即時獎勵 + 下一狀態根據現有學習經驗中最有價值的選擇 X 折扣率 q[current_state][current_action] = current_action_point + gamma * next_state_max_q current_state = next_state print("經驗矩陣:") print(q) start_room = np.random.randint(0, 5) current_state = start_room step = 0 while current_state != target_state: next_state = np.argmax(q[current_state]) print("Agent 由", current_state, "號房間移動到了", next_state, "號房間") current_state = next_state step += 1 print("Agent 在", start_room, "號房間開始移動了", step, "步到達了目標房間 5")
