教你教電腦下圈叉棋

原理

主要是看了這一篇Get a taste of reinforcement learning — implement a tic tac toe agent,裏面作者提出了大概的訓練思路,我基本沒有參照他的具體實現,但是思路肯定是差不多的。而且訓練結果是我幾乎下不過這個AI,比這篇的結果要好很多(不過這種明顯算法可以解決的問題用AI也沒什麼意思)。

實現

核心在於訓練一個模型MM,這個模型用來學習當前的棋局GG時,我們的當前玩家pp該怎麼處理。強化學習不需要訓練用例,而是我們自己產生訓練用例。這是一個有點循環依賴的問題。因爲模型顯然自己不知道該往什麼方向發展,通常的機器學習訓練中,我們的依靠外在的數據讓模型去調整自己的參數。所幸,我們得GG服從一套遊戲規則,這個遊戲規則可以幫助我們產生(越來越好的)訓練用例。

訓練過程

我們的訓練流程是這樣的。圈圈用符號OO,叉叉用符號XX表示。先手圈圈的模型稱爲MOM_O,後手圈圈的模型稱爲MXM_X,他們需要學習一個映射,映射到當前獎勵EpE_pEpE_p代表模型對當前各種走法(圈叉棋中至多9種)的價值的判斷。即
MO=GEOM_O = G\mapsto E_O
MX=GEXM_X = G\mapsto E_X

  1. 初始狀態時我們隨機初始化MOM_OMXM_X
  2. 然後我們利用當前參數的MOM_OMXM_X在盤面上進行搏鬥,即產生(一個batch的)訓練用例。爲了產生更廣泛的訓練樣例,我們採用算法AA來產生隨機的訓練用例(之後定義算法AA)。
  3. 利用訓練用例調整MOM_OMXM_X的參數,返回 2。

算法AA

  1. 隨機產生 bb 盤合法棋局SgS_g,這些棋局滿足遊戲規則,而且當前不存在勝者。
  2. 對於每個棋局 sSgs\in S_g ,如果是輪到選手 OO, 則認爲sSOs \in S_O,否則 sSXs \in S_X
  3. 對於每個棋局 sSgs\in S_g ,按照遊戲規則產生用例。對當前ss中每個空格,填入當前選手的符號。之後按照當前選手,通過MOM_OMXM_X預測獎勵,選擇獎勵最大的位置進行走子(我們會解決當前模型預測獎勵最大的位置不是空格的問題*)。直到當前棋局 ss 分出勝負(或平局)。對每個空格處理完後,我們可以對當前棋局ss按照如下規則進行估算獎勵Ep,sE_{p,s},注意這裏的pp是棋局ss的當前玩家,Ep,sE_{p,s}可以當作一個9元向量,Ep,siE_{p,s}^i是上文所說的當前走位置ii的獎勵,假設我們把棋局ss編號到k[0,9)k\in[0,9)的整數。:
    • 如果 sis^i 已經被佔了,那麼 Ep,siE_{p,s}^i 定義爲 0。
    • 如果 sis^i 在上述過程第一步"填入當前選手的符號"後,經過 stepstep 步勝利了,定義 Ep,si=V(step)E_{p,s}^i = V(step),這裏的 VV 是我們自己定義的函數,它可以是常函數 lambda V : 1 也可以是某個關於 step 的減函數,來促使我們的模型儘早勝利。我們可以定義最優的 Ep,si=1E_{p,s}^i = 1
    • 如果 2 中,經過 stepstep 步後平局或者沒有勝利,定義 Ep,si=F(step)E_{p,s}^i = F(step)。這個 F 也可以自己來定義。根據我的經驗,F是stepstep的增函數會促使模型學會堵子。
  4. 如此一來我們就有了分別面向模型MOM_OMXM_X訓練集TOT_OTXT_X
    TO={(s,EO,s)sSO}T_O = \{ (s, E_{O, s})|s\in S_O \}
    TX={(s,EX,s)sSX}T_X = \{ (s, E_{X, s})|s\in S_X \}

理解

模型訓練的核心顯然在我們爲什麼用算法AA能產生對MOM_OMPM_P有優化作用的訓練用例集TOT_OTXT_X
正如訓練過程(1)所示,一開始MOM_OMPM_P的參數是隨機的,所以我們左右互搏產生的測試用例實際是質量很低的,因爲雙方並沒有建立起如實反映GEPG\mapsto E_P的映射MPM_P。但是我們有強制的一步算法AA的(3),我們對每個空格都進行了試驗,因此至少獲得了一部分 SSgS'\subset S_g 的真實 Ep,sE_{p,s} 值,例如
s=OO_XX____S s = \begin{matrix} O & O & \_ \\ X & X & \_ \\ \_ & \_ & \_ \end{matrix} \in S'

當前選手是OO,那麼。之後我們對Eo,s2=V(1)E_{o,s}^2 = V(1) (假設位置編號從左到右從上到下,從0開始。)便得到了可靠的目標值。然後我們在訓練過程 3. 中利用優化算法,便使得我們的模型對 SS' 有了更加準確的映射。如此而來,由於 MpM_p 變得更加準確了,下一輪便能得到更加高質量的訓練用例。例如當
s=OO_X_____S s' = \begin{matrix} O & O & \_ \\ X & \_ & \_ \\ \_ & \_ & \_ \end{matrix} \in S'
輪到XX走子,對於試驗填入位置 4 ,那麼由於我們的模型MOM_OEO,s2E_{O,s}^2 有較高的價值判斷(從而導致此次試驗XX輸),因此XX將學習避免走位置 44。這樣我們的模型就學習到了SS'以外的正確映射。
當然,這是非常不mathematic的,但是可以作爲一個膚淺的理解。

實驗

  1. 代碼 https://github.com/hanayashiki/TicTacToe (python 3.6, keras, tensorflow)。
  2. 棋局用 GR3×3×3G \in \mathbb{R^{3\times3\times3}} 表示,其中最後一個維度是 (1,0,0)(1, 0, 0) 表示填入 ”O",(0,1,0)(0, 1, 0) 表示是空白,(0,0,1)(0, 0, 1) 表示填入 “X”,採用獨熱編碼是爲了儘量減少假設。
  3. 表現最好的模型定義在 model.py 中的 ModelThreeDensesReluReluAdamMasked。它的結構是
    1. shape=(27,) 的輸入層
    2. 兩層輸出爲 256 維的全連接層,激活函數爲 relu
    3. 全連接輸出層爲 9 維,激活函數爲 relu
    4. mask 層生成 9 維 0-1 mask 對應當前能走的點位 *,因此不能走的地方總是 0,我們的算法不需要學習不符合規則的情況。mask 層按元素與 3 層相連接。 同時由於 relu 可能有全 0 的輸出,我們接着在 mask 層對應的位置加上一個小量 0.0001,避免最終預測結果全 0。
    5. 算法 AA 中的 VVFF 函數進行瞎幾把定義,我這裏保證平局或者輸產生的 Es,pE_{s,p} 取值在 [0,0.4][0, 0.4],隨步數增加;勝利產生的 Es,pE_{s,p}[0.7,1][0.7, 1] 之間。直覺地促使如果輸,那麼要儘量拖延(學會堵子);如果贏,儘量用較少的步數(學會將死)。
  4. 訓練時每次產生 64 個測試用例。loss function 使用 MSE

結果

到了見證結果的激動人心的時間!
經過 3000 輪訓練,MOM_Oloss 達到了 0.002995MXM_Xloss 達到了 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 

總之這個訓練結果,非常有意思!機器僅僅從規則學習到的操作,出乎人類玩家意料!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章