Deep Q-Network 學習筆記(一)—— Q-Learning 學習與實現過程中碰到的一些坑


這方面的資料比較零散,學起來各種碰壁,碰到各種問題,這里就做下學習記錄。

 

參考資料:

https://morvanzhou.github.io/

非常感謝莫煩老師的教程

 

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")

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM