當前位置:
首頁 > 科技 > 用TensorFlow基於神經網路實現井字棋(含代碼)

用TensorFlow基於神經網路實現井字棋(含代碼)

為了展示如何應用神經網路演算法模型,我們將使用神經網路來學習優化井字棋(Tic Tac Toe)。明確井字棋是一種決策性遊戲,並且走棋步驟優化是確定的。

開始

為了訓練神經網路模型,我們有一系列優化的不同的走棋棋譜,棋譜基於棋盤位置列表和對應的最佳落子點。考慮到棋盤的對稱性,通過只關心不對稱的棋盤位置來簡化棋盤。井字棋的非單位變換(考慮幾何變換)可以通過90度、180度、270度、Y軸對稱和X軸對稱旋轉獲得。如果這個假設成立,我們使用一系列的棋盤位置列表和對應的最佳落子點,應用兩個隨機變換,然後賦值給神經網路演算法模型學習。


井字棋是一種決策類遊戲,注意,先下者要麼贏,要麼繼續走棋。我們希望能訓練一個演算法模型給出最佳走棋,使得棋局繼續。

在本例中,棋盤走棋一方「×」用「1」表示,對手「O」用「-1」表示,空格棋用「0」表示。圖 6-9 展示了棋盤的表示方式和走棋:

用TensorFlow基於神經網路實現井字棋(含代碼)

圖6-9 展示棋盤和走棋的表示方式

注意,× = 1,O = -1,空格棋為 0。棋盤位置索引的起始位置標為 0。

除了計算模型損失之外,我們將用兩種方法來檢測演算法模型的性能:第一種檢測方法是,從訓練集中移除一個位置,然後優化走棋。這能看出神經網路演算法模型能否生成以前未有過的走棋(即該走棋不在訓練集中);第二種評估的方法是,直接實戰井字棋遊戲看是否能贏。

不同的棋盤位置列表和對應的最佳落子點數據在 GitHub [1] 中可以查看。

動手做

1.導入必要的編程庫,代碼如下:


import tensorflow as tf

import matplotlib.pyplot as plt

import csv

import random

import numpy as np

import random

2.聲明訓練模型的批量大小,代碼如下:


batch_size = 50

3.為了讓棋盤看起來更清楚,我們創建一個井字棋的列印函數,代碼如下:


def print_board(board):

symbols = ["O"," ","X"]

board_plus1 = [int(x) + 1 for x in board]

print(" " + symbols[board_plus1[0]] + " | " + symbols[board_

plus1[1]] + " | " + symbols[board_plus1[2]])

print("___________")

print(" " + symbols[board_plus1[3]] + " | " + symbols[board_

plus1[4]] + " | " + symbols[board_plus1[5]])

print("___________")

print(" " + symbols[board_plus1[6]] + " | " + symbols[board_

plus1[7]] + " | " + symbols[board_plus1[8]])

4.創建get_symmetry函數,返回變換之後的新棋盤和最佳落子點,代碼如下:


def get_symmetry(board, response, transformation):

"""

:param board: list of integers 9 long:

opposing mark = -1

friendly mark = 1

empty space = 0

:param transformation: one of five transformations on a board:

rotate180, rotate90, rotate270, flip_v, flip_h

:return: tuple: (new_board, new_response)

"""

if transformation == "rotate180":

new_response = 8 - response

return(board[::-1], new_response)

elif transformation == "rotate90":

new_response = [6, 3, 0, 7, 4, 1, 8, 5, 2].index(response)

tuple_board = list(zip(*[board[6:9], board[3:6], board[0:3]]))

return([value for item in tuple_board for value in item], new_response)

elif transformation == "rotate270":

new_response = [2, 5, 8, 1, 4, 7, 0, 3, 6].index(response)

tuple_board = list(zip(*[board[0:3], board[3:6],

board[6:9]]))[::-1]

return([value for item in tuple_board for value in item], new_response)

elif transformation == "flip_v":

new_response = [6, 7, 8, 3, 4, 5, 0, 1, 2].index(response)

return(board[6:9] + board[3:6] + board[0:3], new_response)

elif transformation == "flip_h":

# flip_h = rotate180, then flip_v

new_response = [2, 1, 0, 5, 4, 3, 8, 7, 6].index(response)

new_board = board[::-1]

return(new_board[6:9] + new_board[3:6] + new_board[0:3],

new_response)

else:

raise ValueError("Method not implmented.")

5.棋盤位置列表和對應的最佳落子點數據位於.csv文件中。我們將創建get_moves_from_csv函數來載入文件中的棋盤和最佳落子點數據,並保存成元組,代碼如下:


def get_moves_from_csv(csv_file):

"""

:param csv_file: csv file location containing the boards w/responses

:return: moves: list of moves with index of best response

"""

moves =

with open(csv_file, "rt") as csvfile:

reader = csv.reader(csvfile, delimiter=",")

for row in reader:

moves.append(([int(x) for x in row[0:9]],int(row[9])))

return(moves)

6.創建一個get_rand_move函數,返回一個隨機變換棋盤和落子點,代碼如下:


def get_rand_move(moves, rand_transforms=2):

# This function performs random transformations on a board.

(board, response) = random.choice(moves)

possible_transforms = ["rotate90", "rotate180", "rotate270", "flip_v", "flip_h"]

for i in range(rand_transforms):

random_transform = random.choice(possible_transforms)

(board, response) = get_symmetry(board, response, random_transform)

return(board, response)

7.初始化計算圖會話,載入數據文件,創建訓練集,代碼如下:


sess = tf.Session

moves = get_moves_from_csv("base_tic_tac_toe_moves.csv")

# Create a train set:

train_length = 500

train_set =

for t in range(train_length):

train_set.append(get_rand_move(moves))

8.前面提到,我們將從訓練集中移除一個棋盤位置和對應的最佳落子點,來看訓練的模型是否可以生成最佳走棋。下面棋盤的最佳落子點是棋盤位置索引為6的位置,代碼如下:


test_board = [-1, 0, 0, 1, -1, -1, 0, 0, 1]

train_set = [x for x in train_set if x[0] != test_board]

9.創建init_weights函數和model函數,分別實現初始化模型變數和模型操作。注意,模型中並沒有包含softmax激勵函數,因為softmax激勵函數會在損失函數中出現,代碼如下:


def init_weights(shape):

return(tf.Variable(tf.random_normal(shape)))

def model(X, A1, A2, bias1, bias2):

layer1 = tf.nn.sigmoid(tf.add(tf.matmul(X, A1), bias1))

layer2 = tf.add(tf.matmul(layer1, A2), bias2)

return(layer2)

10.聲明佔位符、變數和模型,代碼如下:


X = tf.placeholder(dtype=tf.float32, shape=[None, 9])

Y = tf.placeholder(dtype=tf.int32, shape=[None])

A1 = init_weights([9, 81])

bias1 = init_weights([81])

A2 = init_weights([81, 9])

bias2 = init_weights([9])

model_output = model(X, A1, A2, bias1, bias2)

11.聲明演算法模型的損失函數,該函數是最後輸出的邏輯變換的平均softmax值。然後聲明訓練步長和優化器。為了將來可以和訓練好的模型對局,我們也需要創建預測操作,代碼如下:


loss = tf.reduce_mean( tf.nn.sparse_softmax_cross_entropy_with_logits(model_output, Y))

train_step = tf.train.GradientDescentOptimizer(0.025).minimize(loss)

prediction = tf.argmax(model_output, 1)

12.初始化變數,遍歷迭代訓練神經網路模型,代碼如下:


# Initialize variables

init = tf.initialize_all_variables

sess.run(init)

loss_vec =

for i in range(10000):

# Select random indices for batch

rand_indices = np.random.choice(range(len(train_set)), batch_size, replace=False)

# Get batch

batch_data = [train_set[i] for i in rand_indices]

x_input = [x[0] for x in batch_data]

y_target = np.array([y[1] for y in batch_data])

# Run training step

sess.run(train_step, feed_dict={X: x_input, Y: y_target})

# Get training loss

temp_loss = sess.run(loss, feed_dict={X: x_input, Y: y_

target})

loss_vec.append(temp_loss)

if i%500==0:

print("iteration " + str(i) + " Loss: " + str(temp_loss))

13.繪製模型訓練的損失函數,代碼如下(對應的圖見圖6-10):


plt.plot(loss_vec, "k-", label="Loss")

plt.title("Loss (MSE) per Generation")

plt.xlabel("Generation")

plt.ylabel("Loss")

plt.show

用TensorFlow基於神經網路實現井字棋(含代碼)

圖6-10 迭代10000次訓練的井字棋模型的損失函數圖

下面繪製模型訓練的損失函數:

1.為了測試模型,將展示如何在測試棋盤(從訓練集中移除的數據)使用。我們希望看到模型能生成預測落子點的索引,並且索引值為6。在大部分情況下,模型都會成功預測,代碼如下:


test_boards = [test_board]

feed_dict = {X: test_boards}

logits = sess.run(model_output, feed_dict=feed_dict)

predictions = sess.run(prediction, feed_dict=feed_dict)

print(predictions)

2.輸出結果如下:


[6]

3.為了能夠評估訓練模型,我們計劃和訓練好的模型進行對局。為了實現該功能,我們創建一個函數來檢測是否贏了棋局,這樣程序才能在該結束的時間喊停,代碼如下:


def check(board):

wins = [[0,1,2], [3,4,5], [6,7,8], [0,3,6], [1,4,7], [2,5,8],[0,4,8], [2,4,6]]

for i in range(len(wins)):

if board[wins[i][0]]==board[wins[i][1]]==board[wins[i][2]]==1.:

return(1)

elif board[wins[i][0]]==board[wins[i][1]]==board[wins[i][2]]==-1.:

return(1)

return(0)

4.現在遍歷迭代,同訓練模型進行對局。起始棋盤為空棋盤,即為全0值;然後詢問棋手要在哪個位置落棋子,即輸入0-8的索引值;接著將其傳入訓練模型進行預測。對於模型的走棋,我們獲得了多個可能的預測。最後顯示井字棋遊戲的樣例。對於該遊戲來說,我們發現訓練的模型表現得並不理想,代碼如下:


game_tracker = [0., 0., 0., 0., 0., 0., 0., 0., 0.]

win_logical = False

num_moves = 0

while not win_logical:

player_index = input("Input index of your move (0-8): ")

num_moves += 1

# Add player move to game

game_tracker[int(player_index)] = 1.

# Get model"s move by first getting all the logits for each

index

[potential_moves] = sess.run(model_output, feed_dict={X:

[game_tracker]})

# Now find allowed moves (where game tracker values = 0.0)

allowed_moves = [ix for ix,x in enumerate(game_tracker) if

x==0.0]

# Find best move by taking argmax of logits if they are in

allowed moves

model_move = np.argmax([x if ix in allowed_moves else -999.0

for ix,x in enumerate(potential_moves)])

# Add model move to game

game_tracker[int(model_move)] = -1.

print("Model has moved")

print_board(game_tracker)

# Now check for win or too many moves

if check(game_tracker)==1 or num_moves>=5:

print("Game Over!")

win_logical = True

5.人機交互的輸出結果如下:


Input index of your move (0-8): 4

Model has moved

O | |

___________

| X |

___________

| |

Input index of your move (0-8): 6

Model has moved

O | |

___________

| X |

___________

X | | O

Input index of your move (0-8): 2

Model has moved

O | | X

___________

O | X |

___________

X | | O

Game Over!

工作原理

我們訓練一個神經網路模型來玩井字棋遊戲,該模型需要傳入棋盤位置,其中棋盤的位置是用一個九維向量來表示的。然後預測最佳落子點。我們需要賦值可能的井字棋棋盤,應用隨機轉換來增加訓練集的大小。

為了測試演算法模型,我們移除一個棋盤位置列表和對應的最佳落子點,然後看訓練模型能否生成預測的最佳落棋點。最後,我們也和訓練模型進行對局,但是結果並不理想,我們仍然需要嘗試不同的架構和訓練方法來提高效果。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 高可用架構 的精彩文章:

美圖在大型容器化平台日誌的實踐(一)選型思考篇
UC瀏覽器快開之路:如何應對大型APP優化工作周而復始難題?
為什麼LinkedIn放棄MySQL slowlog,轉用基於網路層的慢查詢分析器?
Web伺服器如何實現高吞吐低延遲?Dropbox從操作系統到應用層優化指南
全方位解密直播短視頻架構:美圖互聯網技術沙龍來北京了

TAG:高可用架構 |