照例還是先公布代碼 http://download.csdn.net/source/913373
以及編譯好的可執行程式,:http://download.csdn.net/source/913515前面介紹的UCT演算法聽起來很誘人,但是只有你真正去實驗一下你才知道原來有這麼多問題。理論上,UCT是一個一致的演算法,它可以隨著類比次數的增加而自然提高棋力,而且理論上,它還可以計算到任意深度,而且理論上,它是天然支援並行計算的。但是,看看它華麗的外衣下面隱藏著哪些東西吧:一、類比速度和記憶體問題目前的類比速度是讓我滿意的,但是記憶體跟不上,9路棋盤上的5萬局類比+UCT選擇,也只需要1秒多時間,10萬局也就差不多3秒鐘,但是,如果我想持續進行120秒的類比,1G的記憶體也是不夠用的。給我的感覺這個演算法需要的記憶體比並行運算更重要,兩個CPU分別類比5萬次和1個CPU獨自類比10萬次,結果是不同的。如果我有64位的記憶體,我覺得這個演算法的前景會很可觀。隨後我自己想了一種方法來在有限的記憶體中類比較長的時間,就是發現記憶體將要用完時,把勝率不佳的子樹砍掉。但是這個改動破壞了演算法的一致性,我用圍棋實驗的結果就是,AI超喜歡把棋連成一根長棍,而且走棋過程中自我感覺良好,快終局時勝率突然下降到投子認負。這應該就是瞎砍樹導致類比結果失去意義了。二、類比的收斂性這麼來定義這個收斂性吧,如果一番類比下來,所有子節點都差不過,沒有什麼突出的,這就是收斂性差,反之,有少量節點的表現很突出,那麼這個類比的收斂性就好。純發散的類比在五子棋中就是一例:我為五子棋類比定的簡單規則就是隨便下,成五則勝。但是類比結果幾乎毫無意義,導致棋盤中間的子的勝率和棋盤邊緣的沒什麼差別。我只好把類比規則改一下,雙方類比的時候,只在對方和己方棋子的周圍隨機下棋,AI的棋力馬上得到提高,不過這和MC的精神是相衝突的。另外影響收斂性的還有一個因素,你怎麼為節點打分?目前有兩種打分策略:輸贏都計分和只記贏局的分。前者收斂性好,但使得AI的行為非常保守,後者收斂性差,而且使得AI冒進。冒進的例子就是五子棋中,對手活三,AI也活三。保守的例子還是圍棋中的把棋連成棍。三、類比的深度深度和廣度是有矛盾的,為了類比的深一點,AI就要拋棄一些點,這和傳統博弈程式是一致的,如前面說的五子棋的類比,僅局限在棋子周圍,則類比深度很容易就達到9步,但是這樣一來,AI就漏掉了有一定間隔的好手了。但是如果把“周圍”的範圍放寬,類比深度又上不去。至今困擾我的兩個問題,不知道是不是與深度有關:問題一,為什麼五子棋中AI在自己棋勢很好的時候,總是不擋對方的活三呢?問題二,為什麼圍棋中,AI能征吃對方的子,但是它自己老做出逃征子(術語:ladder)的事呢?四、類比的信賴度在為一個節點做類比時,是只類比一次還是類比多次呢?這在代碼中稱為節點的成熟度等級(mature)。如果次數少,則結果的信賴度很成問題,次數太多,深度深度又成問題。而且我發現,圍棋中,次數少時效果較好,而五子棋中則是次數多一點效果比較好。五、接下來怎麼改進在UCT的深淵中掙紮,代碼被改的一團糟,因為太多參數可調,搞的寫程式變成了做測試。現在我還有幾根救命稻草可用。1 不知道能不能找到完美的砍樹演算法,使得在節點記憶體不夠時的砍樹不要造成太大影響。2 把樹換成圖來儲存節點,也就是UCG,不知道能有多大協助。3 並行,是多個單元獨立維護各自的樹,還是通過線程互斥讓它們更新同一棵樹呢?我總覺得多個單元獨立運算就像是狼群去和虎鬥一樣,對它沒什麼信心。4 AMAF,算是UCT的一種改進,據說能用較少的類比次數來得到更多的結果。5 還有一種思路是將類比中出現的難解局面拋給對方,自己只選擇容易處理的局面,不過這種思路似乎更像是克制MC程式而不是克制人類的。