1. 程式人生 > >讓機器玩遊戲的強化學習(附github)

讓機器玩遊戲的強化學習(附github)

強化學習

強化學習是代理面臨的學習問題,它通過與動態環境反覆互動試驗從而學習到某種行為。它是機器學習的主要學習方法之一,智慧體從環境到行為的學習,也就是如何在環境中採取一些列行為,才能使得回報訊號函式的值最大,即獲得的累積回報最大。

現在強化學習與深度學習結合的深度強化學習更加強大。

image

馬爾科夫決策過程

在理解強化學習之前,我們先了解我們要解決什麼樣的問題。其實強化學習過程就是優化馬爾科夫決策過程,它由一個數學模型組成,該模型在代理的控制下對隨機結果進行決策。

image

代理可以執行某些動作,例如上下左右移動,這些動作可能會得到一個回報,回報可以是正數也可以是負數,它會導致總分數變動。同時動作可以改變環境並導致一個新的狀態,然後代理可以執行另外一個動作。狀態、動作和回報的集合、轉換規則等,構成了馬爾科夫決策過程。

決策相關元素

  • 狀態集合,所有可能狀態。
  • 動作集合,所有動作,它能使某個狀態轉換為另一狀態。
  • 狀態轉移概率,特定的狀態下執行不同動作的概率分佈。
  • 回報函式,從一個狀態到另一個狀態所得到的回報。
  • 折扣因子,用於決定未來回報的重要性。

image

強化學習訓練主要就是計算各個狀態下不同動作的回報,並非瞬間完成的,而是要經過大量嘗試。下一個狀態取決於當前狀態和動作,並且狀態不依賴於先前的狀態,沒有記憶,符合馬爾可夫性。

馬爾科夫過程的優化

強化學習是agent與環境之間的迭代互動,需要考慮幾點:

  • 處於某種狀態,決策者將在該狀態下選擇一個動作;
  • 能隨機進入一個新狀態並給決策者相應的回報作為響應;
  • 狀態轉移函式選擇的動作將影響新狀態的選擇;

Q學習

Q學習即是學習不同狀態下各個動作的質量,它定義為

Q_\pi(s,a) = E_\pi[C_t|S_t=s,A_t=a]

它同樣可以變換成Bellman Equation形態,

Q_\pi(s,a) = E_\pi[R_{t+1} +\gamma Q_\pi(S_{t+1},A_{t+1}) | S_t=s,A_t=a]

最優動作價值函式,

Q_*(s,a) = Max_\pi  Q_\pi(s,a)

Q_*(s,a) = E_\pi[MaxR_{t+1} +\gamma Max_{S_{t+1}} Q_\pi(S_{t+1},A_{t+1}) | S_t=s,A_t=a]

可以看到最大化當前的動作價值函式就是最大化當前回報和下一時刻狀態的最優動作價值函式。

動作價值函式雖然能直接計算出Q值,但實際學習時並沒有直接使用該Q值來更新,而是通過漸進的方式來更新。學習的方法可用如下虛擬碼說明,首先初始化Q學習的狀態集和動作集組成的陣列,然後觀察初始狀態,接著不斷重複執行:選擇一個動作,觀察回報並轉移到新狀態,更新Q學習陣列值,涉及迭代方式更新,由於我們不能知道下一刻狀態的Q值,所以更新時用之前迭代的Q值來更新此次迭代的Q值,其中α表示學習率。

initialize Q[numstates,numactions] arbitrarily
observe initial state s
repeat
    select and carry out an action a
    observe reward R and new state s'
    Q[s,a] = Q[s,a] + α(R + γmaxa'Q[s',a'] - Q[s,a])
    s = s'
until terminated
複製程式碼

小遊戲

有個小遊戲,如下圖,進入入口後初始位置為A,陰影部分表示大炕,踩進去就沒命了得重來,操作可以上下左右,最終走到H位置就算勝利。

image

實現Q學習

先定義地圖的大小,以及大坑的位置、入口和出口。

ROWS = 5
COLUMNS = 6
ENTRANCE = (0, 0)
EXIT = (4, 5)
BARRIERS = list()
BARRIERS.append((1, 1))
BARRIERS.append((2, 1))
BARRIERS.append((3, 1))
BARRIERS.append((4, 1))
BARRIERS.append((0, 3))
BARRIERS.append((1, 3))
BARRIERS.append((3, 3))
BARRIERS.append((4, 3))
BARRIERS.append((3, 4))
BARRIERS.append((1, 5))
複製程式碼

定義Q學習的一些引數設定,TIMES為嘗試次數,R為隨機因子,ALPHA為學習率,GAMMA為折扣因子,q_values為q值表,results為最終結果。

TIMES = 200
R = 0.05
ALPHA = 0.1
GAMMA = 0.9
q_values = dict()
results = list()
複製程式碼

初始化q值表,按照行數列數和動作初始化所有q值。

def init_q_values():
    for row in range(0, ROWS):
        for col in range(0, COLUMNS):
            state = State(row, col)
            for action in Actions:
                q = (state.row, state.col, action)
                q_values[q] = 0
複製程式碼

定義某個狀態執行某個動作後得到的新狀態,其中要考慮到地圖的邊緣。

def move(curr_state, action):
    new_state = State(curr_state.row, curr_state.col)
    # check borders
    if action == Actions.up:
        if (new_state.row - 1) >= 0:
            new_state.row -= 1
    elif action == Actions.down:
        if (new_state.row + 1) <= (ROWS - 1):
            new_state.row += 1
    elif action == Actions.left:
        if (new_state.col - 1) >= 0:
            new_state.col -= 1
    elif action == Actions.right:
        if (new_state.col + 1) <= (COLUMNS - 1):
            new_state.col += 1
    return new_state
複製程式碼

定義每一步的探索方法,分別執行不同動作找到最優的動作,此外還需要有一定概率的隨機動作選擇。

def explore(curr_state):
    rand = random.random()
    if rand <= R:
        return random.choice(list(Actions))
    else:
        best = list()
        best_action = Actions.up
        best_value = -10000000
        for action in Actions:
            q = (curr_state.row, curr_state.col, action)
            if q_values[q] > best_value:
                best_action = action
                best_value = q_values[q]
        best.append(best_action)
        # perhaps it has not only one best action
        for action in Actions:
            q = (curr_state.row, curr_state.col, action)
            if action != best_action:
                if q_values[q] == best_value:
                    best.append(action)
        return random.choice(best)
複製程式碼

定義更新狀態操作,一旦選出最優的動作後將進行狀態的更新,也就是更新q值表,如果到達出口則回報為0,如果掉入大坑則回報為-100。

def update(curr_state, last_action):
    q = (curr_state.row, curr_state.col, last_action)
    new_state = move(curr_state, last_action)
    position = (new_state.row, new_state.col)
    reward = -1
    if position == EXIT:
        reward = 0
    elif position in BARRIERS:
        reward = -100
    old_value = q_values[q]
    max_new = max([q_values[(new_state.row, new_state.col, a)] for a in Actions])
    q_values[q] = old_value + ALPHA * (reward + (GAMMA * max_new) - old_value)
    curr_state.row = new_state.row
    curr_state.col = new_state.col
複製程式碼

比如我們訓練200次後,最終根據q值表就可以找到最佳的執行動作序列如下,說明經過這些動作操作後能成功到達出口。

Actions.right
Actions.right
Actions.down
Actions.down
Actions.right
Actions.right
Actions.right
Actions.down
Actions.down
Actions.down
複製程式碼

github

github.com/sea-boat/Ma…

-------------推薦閱讀------------

我的開源專案彙總(機器&深度學習、NLP、網路IO、AIML、mysql協議、chatbot)

為什麼寫《Tomcat核心設計剖析》

我的2017文章彙總——機器學習篇

我的2017文章彙總——Java及中介軟體

我的2017文章彙總——深度學習篇

我的2017文章彙總——JDK原始碼篇

我的2017文章彙總——自然語言處理篇

我的2017文章彙總——Java併發篇


跟我交流,向我提問:

歡迎關注: