上次乙個網友建議我用遺傳演算法,不過當時我沒有找到合適的遺傳因子,其實根本原因是我那時候正在手工測試程式的棋力,我自己和程式下,發現問題,然後看看怎麼改進。這個過程中其實帶有太強的主觀色彩了,直到一周前我正式摒棄了ucg的想法,我才終於決定用自然選擇的方式來測試程式的棋力。
前面的文章中提到過ucg的思想,也就是認為博弈樹實際上應該看做是乙個圖,因為下棋時的每乙個局面,都可以用不止一種順序走出來,也就是每個節點不止乙個父節點。我剛接觸uct演算法時,就想到了這一點,而且奇怪為何沒人這麼做,總覺得如果按照圖來處理,模擬的結果應該更逼近真實情況吧!因為圖的處理比樹麻煩,還是使用樹結構去做了。
再後來,我發現計算機圍棋論壇上也有人提出ucg,而我又想到了可以用置換表等效的實現後,很是興奮,人都是會對自己的想法誇大優點,並且無意中忽略缺點。例如我對我實現的ucg多占用的一倍記憶體視而不見,速度比uct慢我也能接受,並且出於良好的自我感覺,在與程式對戰後,我做出了「ucg使得程式棋力立即有了提高」的判斷。
幸好我在進一步改進ucg機制前,我寫了個指令碼讓兩個程式之間對戰。並從對戰結果中發現乙個殘酷的事實:使用ucg的程式完敗。
在事實面前,我才想明白了原由:uct演算法本身是乙個對所有節點公平的演算法,如果某個節點在樹中有同型節點存在,那麼其任何乙個兄弟節點也存在同型節點。而ucg的作用是使乙個節點的模擬結果被其全部同型節點共享,共享或者不共享,影響的只是對節點過往勝率的重視程度,但是uct演算法本身就有調節這種重視程度的機制,還記得uct的本質嗎?就是在開發和探索之間尋求一種平衡,對過往勝率的重視就意味著把開發的權重加大。
這就是說我挖空心思做的乙個ucg改進沒有絲毫意義,它的效果可以通過調整ucb公式的引數模擬出來。
這是一種最大限度利用模擬結果的手段,all moves as first,即所有的棋步都像第一步一樣。例如,黑棋假設它在a1處下一步棋,然後進行模擬,模擬結果為黑胜,那麼傳統的uct計分方法是為a1這個節點加一分,並把結果向a1的祖先節點彙總,也就是把黑棋勝利歸功於a1這步棋。而按照amaf的做法,則是把功勞均攤到a1以及模擬對局中黑方所下的每乙個位置。
這個方法的優點在於能用少量的模擬局數獲取大量的得分情況,從而加快局面評估速度。但是其缺點和優點一樣突出,在棋類遊戲中的乙個常識是,棋步的順序是與勝負有關係的。這樣的快速評估很可能會得出錯誤的結論。因此,amaf不是乙個一致的演算法。
乙個折中的做法是設定乙個分割比率,只對模擬對局前一部分的棋步計分,通常我們認為先下的棋步要比後下的棋重要。這個比率的取值從0到1,顯而易見,如果取0,演算法就還原為原始的uct了;如果取1,則又相當於乙個完整的amaf了。取什麼樣的值,我用自然選擇來決定。
遺傳因子我已經選好了,一共3個,分別是節點的成熟度(乙個節點被模擬多少局後才為其建立子節點,going down的說法是ooxx多少次後才生娃),探險的權重,amaf的分割比率。
維護乙個種群數量不變,每次隨機取出兩個遺傳因子不同的個體,讓它們分先下兩局棋,輸了的殺掉,贏了的可以無性繁殖乙個後代,繁殖的過程中有一定機率發生變異。如果沒有分出勝負,那也不能讓它們無限的活下去,無論勝負,每下一次棋,生命減1,生命到0也直接抹掉。然後我會再隨機創造新的個體去補齊數量的。
聽起來頗有造物主的感覺呀,進化將會是乙個漫長的過程,為了讓它們下的棋有意義,我每步棋給了它們足足一秒鐘的思考時間。從本文開始寫作時,它們的競爭已經開始了,到現在,預先設定的兩個種子選手之一已經被淘汰掉了乙個,不過離進化的終點還差的很遠,按照遊戲規則,這場進化的結束條件是全部的個體都擁有相同的遺傳因子。
程式實現上,我採用了unix的傳統,用c實現核心部分,指令碼語言作為黏合劑。至於**,實在沒什麼新東西,無非是測試和調整了些引數,我也懶得一遍遍上傳了。實現自然選擇的指令碼我貼在下面,有興趣可以參考。
}# <1>步長變異
# <2>高斯變異
# 這裡用的是步長變異
sub mutate
}if(rand 1 > 0.5) else
return
$value;
}sub match else
}print "--$gid1,$gid2/n";
return 0;
}while(!$time_to_die)
my $randrow = int(rand($max_count));
$sth = $dbh->prepare("select * from renju limit $randrow,1");
$sth->execute();
my @a1 = $sth->fetchrow();
$sth->finish;
my $gid1 = $a1[1];
$sth = $dbh->prepare("select count(id) as n from renju where gid <> $gid1");
my $numrows;
$sth->execute();
$sth->bind_columns(undef, /$numrows);
$sth->fetch;
$sth->finish;
die"selection finished!" unless($numrows);
$randrow = int(rand($numrows));
$sth = $dbh->prepare("select * from renju where gid <> $gid1 limit $randrow,1");
$sth->execute();
my @a2 = $sth->fetchrow();
my $result = match(/@a1, /@a2);
if(!$time_to_die)
if($result > 0) elsif ($result
< 0) else
$dbh->do("delete from renju where life<=0");
} # end
while
$dbh->disconnect();
print "exit.../n";
騰訊圍棋AI技術PhoenixGo正式開源
乙個好的圍棋ai,需要演算法 工程實現 計算資源三者結合。目前圍棋ai已經有了優秀的公開演算法,但同時擁有良好工程實現和大量計算資源,並不是一件容易的事。經過了一周多時間的籌備,phoenixgo目前正式開源了對弈原始碼和乙個20 block的模型。這份原始碼和模型可以在單塊gpu上提供強職業棋手的...
我的AI之路
緒論 本章以西瓜為例子,簡單的介紹了機器學習的一些相關的概念,為之後的學習打下基礎。模型評估與選擇 學習筆記 機器學習之特徵工程 學習筆記 sklearn資料集與估計器 學習筆記 分類演算法 k近鄰演算法 學習筆記 分類演算法 樸素貝葉斯演算法 學習筆記 分類模型的評估 學習筆記 模型的選擇與調優 ...
AI連圍棋都可以大勝,何況遊戲
以前吾是堅決不相信,ai能夠在圍棋方面占用人類。然後事實是,李世石唯一的勝局,可能是人類的唯一。後來再看柯潔跟圍棋下,完全被壓著打,一點機會都沒有。個人感覺可能要讓兩個子。為何吾很震驚?因為圍棋涉及到靈感 直覺,現在可以通過計算得到,實在是 記得柯潔一盤棋中,的一步妙招,得到眾多高手的一致稱讚,可以...