構(gòu)建一個(gè)能夠打敗人類的圍棋神經(jīng)網(wǎng)絡(luò)

上一節(jié)贮预,我們從圍棋服務(wù)器中下載大量棋譜,并將其轉(zhuǎn)換成網(wǎng)絡(luò)可以解析的數(shù)據(jù)格式契讲,在神經(jīng)網(wǎng)絡(luò)的開(kāi)發(fā)中完成了最繁瑣的一步仿吞,也就是數(shù)據(jù)準(zhǔn)備。接下來(lái)我們將創(chuàng)建一個(gè)神經(jīng)網(wǎng)絡(luò)捡偏,對(duì)數(shù)據(jù)進(jìn)行解讀唤冈,使得網(wǎng)絡(luò)具備6到7段的圍棋專業(yè)水平,它尚未具備打敗柯潔或李世石這些頂級(jí)高手的能力银伟,但打敗業(yè)余級(jí)高手則綽綽有余你虹。

我們要完成的網(wǎng)絡(luò)有三種形態(tài)慨削,一種是小型網(wǎng)絡(luò)概荷,一種是中型網(wǎng)絡(luò)嗓化,一種是大型網(wǎng)絡(luò)抚恒,其能力由弱到強(qiáng)糯俗,當(dāng)然訓(xùn)練的耗時(shí)也由少到多珍手。網(wǎng)絡(luò)的基本結(jié)構(gòu)是真竖,前4層我們都使用卷積層荐开,最后一層是一個(gè)含有19*19個(gè)神經(jīng)元的全連接層模孩。這里我們將引入一種新的網(wǎng)絡(luò)層叫ZeroPadding2D層尖阔。卷積網(wǎng)絡(luò)在處理圖像時(shí),它會(huì)把圖像分割成多個(gè)小塊后分別識(shí)別榨咐,識(shí)別所得的結(jié)果在規(guī)格上介却,也就是寬和高上相對(duì)于輸入時(shí)的數(shù)據(jù)而言會(huì)有所縮小,如果卷積層較多块茁,那么圖片在層層處理后齿坷,規(guī)格會(huì)嚴(yán)重減小桂肌。

為了防止規(guī)格縮小得太嚴(yán)重,我們?cè)趯D片輸入卷積網(wǎng)絡(luò)前永淌,會(huì)給它填充若干行和列崎场,假設(shè)我們要處理的圖片規(guī)格為19*19,如果我們執(zhí)行下面語(yǔ)句:

ZeroPadding2D(padding = 2, input_shape = input_shape, data_format='channel_first')

那意味著我們?cè)?919的二維數(shù)組左邊和右邊分別添加2列遂蛀,在上面和底部分別添加2行谭跨,這些列和行全部使用0來(lái)填充,于是就能得到一個(gè)2323的二維數(shù)組李滴。當(dāng)我們把輸入數(shù)據(jù)先擴(kuò)大螃宙,經(jīng)過(guò)卷積網(wǎng)絡(luò)處理后就不會(huì)嚴(yán)重縮水。

同時(shí)我們還得注意所坯,在卷積層谆扎,我們會(huì)用多個(gè)過(guò)濾器對(duì)圖片進(jìn)行掃描,圖片被一個(gè)過(guò)濾器掃描后就得到一個(gè)二維數(shù)組作為掃描結(jié)果芹助,如果多個(gè)過(guò)濾器就會(huì)得到多個(gè)二維數(shù)組堂湖,如下圖:

filters.png

過(guò)濾器的個(gè)數(shù),我們也叫做channel周瞎,上面代碼中channel_first苗缩,表示卷積網(wǎng)絡(luò)輸出結(jié)果中饵蒂,把過(guò)濾器的數(shù)值放在掃描結(jié)果對(duì)應(yīng)的二維數(shù)組前面声诸,假設(shè)卷積層網(wǎng)絡(luò)有N個(gè)過(guò)濾器,每個(gè)過(guò)濾器掃描圖片后得到的結(jié)果二維數(shù)組為W和H退盯,于是上面‘channel_first'指定卷積層輸出的結(jié)果為:[N, W, H]彼乌,也就是把過(guò)濾器的個(gè)數(shù)放在結(jié)果向量的前面。

有了上面的基本解釋后渊迁,我將用代碼構(gòu)造如下結(jié)構(gòu)的神經(jīng)網(wǎng)絡(luò):

Layer (type)                 Output Shape              Param #   
=================================================================
zero_padding2d_5 (ZeroPaddin (None, 1, 25, 25)         0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 48, 19, 19)        2400      
_________________________________________________________________
activation_6 (Activation)    (None, 48, 19, 19)        0         
_________________________________________________________________
zero_padding2d_6 (ZeroPaddin (None, 48, 23, 23)        0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 32, 19, 19)        38432     
_________________________________________________________________
activation_7 (Activation)    (None, 32, 19, 19)        0         
_________________________________________________________________
zero_padding2d_7 (ZeroPaddin (None, 32, 23, 23)        0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 32, 19, 19)        25632     
_________________________________________________________________
activation_8 (Activation)    (None, 32, 19, 19)        0         
_________________________________________________________________
zero_padding2d_8 (ZeroPaddin (None, 32, 23, 23)        0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 32, 19, 19)        25632     
_________________________________________________________________
activation_9 (Activation)    (None, 32, 19, 19)        0         
_________________________________________________________________
flatten_2 (Flatten)          (None, 11552)             0         
_________________________________________________________________
dense_3 (Dense)              (None, 512)               5915136   
_________________________________________________________________
activation_10 (Activation)   (None, 512)               0         
_________________________________________________________________
dense_4 (Dense)              (None, 361)               185193    
=================================================================
Total params: 6,192,425
Trainable params: 6,192,425
Non-trainable params: 0

有了上面網(wǎng)絡(luò)后慰照,我們?cè)偻ㄟ^(guò)上節(jié)實(shí)現(xiàn)的數(shù)據(jù)加載方法,將棋盤數(shù)據(jù)輸入網(wǎng)絡(luò)進(jìn)行訓(xùn)練琉朽,完成后網(wǎng)絡(luò)就具備了能打敗業(yè)余高手的能力毒租。通過(guò)上面網(wǎng)絡(luò)加上人類棋譜的訓(xùn)練,網(wǎng)絡(luò)對(duì)棋手下一步走法的預(yù)測(cè)率能高達(dá)85%作用箱叁,注意到網(wǎng)絡(luò)預(yù)測(cè)的是專業(yè)六段和七段棋手的走法墅垮,因此它能輕易打敗業(yè)余級(jí)的高手。

接下來(lái)我們看看具體代碼的實(shí)現(xiàn):

from keras.layers.core import Dense, Activation, Flatten
from keras.layers.convolutional import Conv2D, ZeroPadding2D

def  layers(input_shape):
  return  [
      ZeroPadding2D(padding  =3, input_shape = input_shape,
                    data_format = 'channels_first'),
      Conv2D(48, (7,7), data_format = 'channels_first'),
      Activation('relu'),
      
      ZeroPadding2D(padding = 2, data_format = 'channels_first'),
      Conv2D(32, (5,5), data_format = 'channels_first'),
      Activation('relu'),
      
      ZeroPadding2D(padding = 2, data_format = 'channels_first'),
      Conv2D(32, (5,5), data_format = 'channels_first'),
      Activation('relu'),
      
      ZeroPadding2D(padding = 2, data_format = 'channels_first'),
      Conv2D(32, (5,5), data_format = 'channels_first'),
      Activation('relu'),
      
      Flatten(),
      Dense(512),
      Activation('relu'),
      
      
  ]

上面代碼構(gòu)造了網(wǎng)絡(luò)各個(gè)處理層耕漱,我們把網(wǎng)絡(luò)層作為單獨(dú)對(duì)象放在一個(gè)隊(duì)列中的好處是算色,后面我們可以根據(jù)需要進(jìn)行加載,如果我們想讓網(wǎng)絡(luò)處理能力更強(qiáng)螟够,那么就多加載幾個(gè)網(wǎng)絡(luò)層灾梦,如果希望處理能力小一些峡钓,就可以加載少一些網(wǎng)絡(luò)層,如此能讓網(wǎng)絡(luò)的構(gòu)建更加靈活若河。

接下來(lái)我們通過(guò)調(diào)用上面函數(shù)構(gòu)建整個(gè)網(wǎng)絡(luò):

#encoder.num_planes對(duì)應(yīng)channel
input_shape = (encoder.num_planes, go_board_rows, go_board_cols) 
#將網(wǎng)絡(luò)層一層層加進(jìn)來(lái)
network_layers = layers(input_shape)
model = Sequential()
for layer in network_layers:
  model.add(layer)

model.add(Dense(num_classes, activation = 'softmax'))
model.compile(loss = 'categorical_crossentropy', optimizer = 'sgd',
             metrics = ['accuracy'])
model.summary()

上面代碼生成的就是前面我們展示的網(wǎng)絡(luò)結(jié)構(gòu)能岩,有了網(wǎng)絡(luò)后,我們加載數(shù)據(jù)為網(wǎng)絡(luò)的訓(xùn)練和驗(yàn)證做準(zhǔn)備:

#加載訓(xùn)練數(shù)據(jù)和測(cè)試數(shù)據(jù),這個(gè)過(guò)程相當(dāng)耗時(shí)
processor = GoDataProcessor(encoder = encoder.name())
generator = processor.load_go_data('train', num_games, use_generator = True)
test_generator = processor.load_go_data('test', num_games, use_generator = True)

然后就可以啟動(dòng)網(wǎng)絡(luò)的訓(xùn)練流程了:


#由于數(shù)據(jù)加載過(guò)程耗時(shí)牡肉,這段訓(xùn)練過(guò)程在沒(méi)有足夠算力情況下很難執(zhí)行
model.fi_generator(generator = generator.generate(batch_size, num_classes),
                    epochs = epochs, 
                    steps_per_epoch = generator.get_num_samples() / batch_size,
                    validation_data = test_generator.generate(batch_size, num_classes),
                    validation_step = test_generator.get_num_samples() / batch_size,
                    callbacks = [
                        ModelCheckpoint('/content/gdrive/My Drive/GO_RECORD/checkpoints/small_model_epoch{epoch}.h5')
                    ]
                   )

一個(gè)問(wèn)題在于捧灰,訓(xùn)練過(guò)程非常耗時(shí),在沒(méi)有GPU或相關(guān)算力支持的情況下我們需要等待很久時(shí)間才能完成整改訓(xùn)練流程统锤,幸運(yùn)的是我們可以直接加載已經(jīng)訓(xùn)練好的網(wǎng)絡(luò)參數(shù)毛俏,直接越過(guò)耗時(shí)耗力的訓(xùn)練過(guò)程:

from keras.models import load_model
model = load_model('/content/gdrive/My Drive/GO_RECORD/small_model_epoch_5.h5')
#幸運(yùn)的是,已經(jīng)有訓(xùn)練好的網(wǎng)絡(luò)饲窿,我們可以跳過(guò)煩瑣的訓(xùn)練階段煌寇,直接加載訓(xùn)練好的網(wǎng)絡(luò)參數(shù)以檢驗(yàn)效果
model.evaluate_generator(generator = test_generator.generate(batch_size, num_classes),
                        steps = test_generator.get_num_samples() / batch_size)

上面代碼中small_model_epoch_5.h5是已經(jīng)訓(xùn)練好的網(wǎng)絡(luò)參數(shù)存儲(chǔ)文件,我們將其直接加載到我們的網(wǎng)絡(luò)結(jié)構(gòu)中從而省略掉訓(xùn)練過(guò)程逾雄,得到最終網(wǎng)絡(luò)后阀溶,我們將其直接應(yīng)用在測(cè)試數(shù)據(jù)上,運(yùn)行后可發(fā)現(xiàn)鸦泳,網(wǎng)絡(luò)對(duì)數(shù)據(jù)預(yù)測(cè)的準(zhǔn)確率達(dá)到85%以上银锻,由于它預(yù)測(cè)的是六段和七段專業(yè)選手的落子,因此這樣的準(zhǔn)確率足以打敗業(yè)余級(jí)別的高水平人類選手做鹰。

更詳細(xì)的講解和代碼調(diào)試演示過(guò)程击纬,請(qǐng)點(diǎn)擊鏈接

新書(shū)上架,請(qǐng)諸位朋友多多支持:
WechatIMG1.jpeg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末钾麸,一起剝皮案震驚了整個(gè)濱河市更振,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饭尝,老刑警劉巖肯腕,帶你破解...
    沈念sama閱讀 212,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異钥平,居然都是意外死亡实撒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門涉瘾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)知态,“玉大人,你說(shuō)我怎么就攤上這事睡汹‰鹊椋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,369評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵囚巴,是天一觀的道長(zhǎng)原在。 經(jīng)常有香客問(wèn)我友扰,道長(zhǎng),這世上最難降的妖魔是什么庶柿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,799評(píng)論 1 285
  • 正文 為了忘掉前任村怪,我火速辦了婚禮,結(jié)果婚禮上浮庐,老公的妹妹穿的比我還像新娘甚负。我一直安慰自己,他們只是感情好审残,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,910評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布梭域。 她就那樣靜靜地躺著,像睡著了一般搅轿。 火紅的嫁衣襯著肌膚如雪病涨。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,096評(píng)論 1 291
  • 那天璧坟,我揣著相機(jī)與錄音既穆,去河邊找鬼。 笑死雀鹃,一個(gè)胖子當(dāng)著我的面吹牛幻工,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播黎茎,決...
    沈念sama閱讀 39,159評(píng)論 3 411
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼囊颅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了工三?” 一聲冷哼從身側(cè)響起迁酸,我...
    開(kāi)封第一講書(shū)人閱讀 37,917評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤先鱼,失蹤者是張志新(化名)和其女友劉穎俭正,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體焙畔,經(jīng)...
    沈念sama閱讀 44,360評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掸读,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,673評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宏多。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片儿惫。...
    茶點(diǎn)故事閱讀 38,814評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖伸但,靈堂內(nèi)的尸體忽然破棺而出肾请,到底是詐尸還是另有隱情,我是刑警寧澤更胖,帶...
    沈念sama閱讀 34,509評(píng)論 4 334
  • 正文 年R本政府宣布铛铁,位于F島的核電站隔显,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏饵逐。R本人自食惡果不足惜括眠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,156評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望倍权。 院中可真熱鬧掷豺,春花似錦、人聲如沸薄声。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)默辨。三九已至生年,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間廓奕,已是汗流浹背抱婉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,123評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桌粉,地道東北人蒸绩。 一個(gè)月前我還...
    沈念sama閱讀 46,641評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像铃肯,于是被迫代替她去往敵國(guó)和親患亿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,728評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容