原理
主要是看了這一篇Get a taste of reinforcement learning — implement a tic tac toe agent,裏面作者提出了大概的訓練思路,我基本沒有參照他的具體實現,但是思路肯定是差不多的。而且訓練結果是我幾乎下不過這個AI,比這篇的結果要好很多(不過這種明顯算法可以解決的問題用AI也沒什麼意思)。
實現
核心在於訓練一個模型,這個模型用來學習當前的棋局時,我們的當前玩家該怎麼處理。強化學習不需要訓練用例,而是我們自己產生訓練用例。這是一個有點循環依賴的問題。因爲模型顯然自己不知道該往什麼方向發展,通常的機器學習訓練中,我們的依靠外在的數據讓模型去調整自己的參數。所幸,我們得服從一套遊戲規則,這個遊戲規則可以幫助我們產生(越來越好的)訓練用例。
訓練過程
我們的訓練流程是這樣的。圈圈用符號,叉叉用符號表示。先手圈圈的模型稱爲,後手圈圈的模型稱爲,他們需要學習一個映射,映射到當前獎勵。代表模型對當前各種走法(圈叉棋中至多9種)的價值的判斷。即
- 初始狀態時我們隨機初始化 和 。
- 然後我們利用當前參數的,在盤面上進行搏鬥,即產生(一個batch的)訓練用例。爲了產生更廣泛的訓練樣例,我們採用算法來產生隨機的訓練用例(之後定義算法)。
- 利用訓練用例調整和的參數,返回 2。
算法
- 隨機產生 盤合法棋局,這些棋局滿足遊戲規則,而且當前不存在勝者。
- 對於每個棋局 ,如果是輪到選手 , 則認爲,否則 。
- 對於每個棋局 ,按照遊戲規則產生用例。對當前中每個空格,填入當前選手的符號。之後按照當前選手,通過 或 預測獎勵,選擇獎勵最大的位置進行走子(我們會解決當前模型預測獎勵最大的位置不是空格的問題*)。直到當前棋局 分出勝負(或平局)。對每個空格處理完後,我們可以對當前棋局按照如下規則進行估算獎勵,注意這裏的是棋局的當前玩家,可以當作一個9元向量,是上文所說的當前走位置的獎勵,假設我們把棋局編號到的整數。:
- 如果 已經被佔了,那麼 定義爲 0。
- 如果 在上述過程第一步"填入當前選手的符號"後,經過 步勝利了,定義 ,這裏的 是我們自己定義的函數,它可以是常函數
lambda V : 1
也可以是某個關於step
的減函數,來促使我們的模型儘早勝利。我們可以定義最優的 。 - 如果 2 中,經過 步後平局或者沒有勝利,定義 。這個 F 也可以自己來定義。根據我的經驗,F是的增函數會促使模型學會堵子。
- 如此一來我們就有了分別面向模型和訓練集和。
理解
模型訓練的核心顯然在我們爲什麼用算法能產生對和有優化作用的訓練用例集和。
正如訓練過程(1)所示,一開始和的參數是隨機的,所以我們左右互搏產生的測試用例實際是質量很低的,因爲雙方並沒有建立起如實反映的映射。但是我們有強制的一步算法的(3),我們對每個空格都進行了試驗,因此至少獲得了一部分 的真實 值,例如
當前選手是,那麼。之後我們對 (假設位置編號從左到右從上到下,從0開始。)便得到了可靠的目標值。然後我們在訓練過程 3. 中利用優化算法,便使得我們的模型對 有了更加準確的映射。如此而來,由於 變得更加準確了,下一輪便能得到更加高質量的訓練用例。例如當
輪到走子,對於試驗填入位置 4 ,那麼由於我們的模型對 有較高的價值判斷(從而導致此次試驗輸),因此將學習避免走位置 。這樣我們的模型就學習到了以外的正確映射。
當然,這是非常不mathematic的,但是可以作爲一個膚淺的理解。
實驗
- 代碼 https://github.com/hanayashiki/TicTacToe (python 3.6, keras, tensorflow)。
- 棋局用 表示,其中最後一個維度是 表示填入 ”O", 表示是空白, 表示填入 “X”,採用獨熱編碼是爲了儘量減少假設。
- 表現最好的模型定義在
model.py
中的ModelThreeDensesReluReluAdamMasked
。它的結構是shape=(27,)
的輸入層- 兩層輸出爲 256 維的全連接層,激活函數爲
relu
- 全連接輸出層爲 9 維,激活函數爲
relu
- mask 層生成 9 維 0-1 mask 對應當前能走的點位 *,因此不能走的地方總是 0,我們的算法不需要學習不符合規則的情況。mask 層按元素與 3 層相連接。 同時由於
relu
可能有全 0 的輸出,我們接着在 mask 層對應的位置加上一個小量 0.0001,避免最終預測結果全 0。 - 算法 中的 和 函數進行瞎幾把定義,我這裏保證平局或者輸產生的 取值在 ,隨步數增加;勝利產生的 在 之間。直覺地促使如果輸,那麼要儘量拖延(學會堵子);如果贏,儘量用較少的步數(學會將死)。
- 訓練時每次產生 64 個測試用例。loss function 使用
MSE
。
結果
到了見證結果的激動人心的時間!
經過 3000 輪訓練,的loss
達到了 0.002995
,的loss
達到了 0.00329
,這說明機器左右互搏的預測已經相當準確了,那麼和人下一盤呢?
New game!
>> Select your role: 'X' or 'O'. o
_ _ _
_ _ _
_ _ _
key >>s // 下方是我的走法
_ _ _
_ O _
_ _ _
_ _ X
_ O _
_ _ _
key >>c
_ _ X
_ O _
_ _ O
X _ X
_ O _
_ _ O
key >>w
X O X
_ O _
_ _ O
X O X
_ O _
_ X O
key >>a
X O X
O O _
_ X O
X O X
O O X
_ X O
key >>z
X O X
O O X
O X O
It's a tie !
可見電腦後手有一定的智能,和我打平了。它的先手更有出乎意料的操作。
>> Select your role: 'X' or 'O'. X
_ _ _
_ _ _
_ _ _
_ _ O // 電腦沒有像我們人一樣選擇中間位置
_ _ _
_ _ _
key >>s
_ _ O
_ X _
_ _ _
_ _ O
_ X _
O _ _
key >>c
_ _ O
_ X _
O _ X
O _ O
_ X _ // 將死了隨便下的我
O _ X
key >>x
O _ O
_ X _
O X X
O O O
_ X _
O X X
Player O wins !
極限操作方可平局:
New game!
>> Select your role: 'X' or 'O'. x
_ _ _
_ _ _
_ _ _
_ _ O
_ _ _
_ _ _
key >>s
_ _ O
_ X _
_ _ _
_ _ O
_ X _
O _ _
key >>a
_ _ O
X X _
O _ _
_ _ O
X X O
O _ _
key >>c
_ _ O
X X O
O _ X
O _ O
X X O
O _ X
key >>w
O X O
X X O
O _ X
O X O
X X O
O O X
It's a tie !
看看機器左右互搏的情況(最後是平局)
_ _ O
_ _ _
_ _ _
_ _ O
_ X _
_ _ _
_ _ O
_ X _
O _ _
_ _ O
_ X _
O X _
_ O O
_ X _
O X _
X O O
_ X _
O X _
X O O
_ X _
O X O
X O O
_ X X
O X O
X O O
O X X
O X O
總之這個訓練結果,非常有意思!機器僅僅從規則學習到的操作,出乎人類玩家意料!