шахматная нейросеть на python
Всем привет! Пытаюсь тут написать шахматную нейросеть, которая хотя бы не будет зевать фигуры в один ход во время игры. Использую обычный перцептрон, обучение с учителем (в качестве обучающей выборки взял партии лучших шахматистов в истории). На входе - 64 нейрона, каждая фигура имеет своё значение в диапазоне (0, 1], пустая клетка - это ноль, дальше два скрытых слоя и выходной - из 128 нейронов, которые условно делятся пополам, первая часть отвечает за поле, на котором стоит фигура, вторая - за поле, на которую перемещают фигуру. Особенность обучения состоит в том, что я исследую только миттельшпильные позиции и эндшпильные, так как в дебюте через нейросеть пройдёт много разных ходов, сделанных в одинаковых позициях (е2-е4, д2-д4 и т.д.) и она просто запутается. Количество партий в обучающей выборке всего порядка 15-20 тысяч. В общем, много слов, вот код:
import chess
import chess.pgn
import numpy as np
from glob import glob
import shelve
# creating a virtual chessboard
from random import *
def f(x):
return 1/(1 + np.exp(-x))
def df(x):
return x*(1-x)
def go_forward(inp):
sum = []
sum = np.dot(W1, inp)
out = np.array([f(x) for x in sum])
sum = np.dot(W2, out)
out2 = np.array([f(x) for x in sum])
sum = np.dot(W3, out2)
y = np.array([f(x) for x in sum])
return (y, out, out2)
def train(epoch, N):
global W2, W1, W3
lmd = 0.1 # шаг обучения
count = len(epoch)
for k in range(N):
if k % 10000 == 0:
print(k // 10000, '%', sep='')
x = epoch[np.random.randint(0, count)] # случайных выбор входного сигнала из обучающей выборки
y, out, out2 = go_forward(x[0:-1]) # прямой проход по НС и вычисление выходных значений нейронов
e = y - np.array(x[-1]) # ошибка
delta = e*df(y) # локальный градиент
for i in range(128):
W3[i, :] = W3[i, :] - lmd * delta[i] * out2
delta2 = []
for i in range(10):
s = 0
for j in range(128):
s += W3[j, i] * delta[j]
delta2 += [s * df(out2[i])]
# корректировка связей первого слоя
for i in range(10):
W2[i, :] = W2[i, :] - out * delta2[i] * lmd
delta3 = []
for i in range(10):
s = 0
for j in range(10):
s += W2[i, j] * delta2[j]
delta3 += [s * df(out[i])]
for i in range(10):
W1[i, :] = W1[i, :] - np.array(x[:-1]) * delta3[i] * lmd
W1 = np.array([[randrange(-100, 101) / 100 for i in range(64)] for j in range(10)])
W2 = np.array([[randrange(-100, 101) / 100 for i in range(10)] for j in range(10)])
W3 = np.array([[randrange(-100, 101) / 100 for i in range(10)] for j in range(128)])
epoch = []
def piece_to_num(piece):
if piece == '.':
return 0
if piece == 'P':
return 1
if piece == 'p':
return 7
if piece == 'N':
return 2
if piece == 'n':
return 8
if piece == 'B':
return 3
if piece == 'b':
return 9
if piece == 'R':
return 4
if piece == 'r':
return 10
if piece == 'Q':
return 5
if piece == 'q':
return 11
if piece == 'K':
return 6
if piece == 'k':
return 12
def board_to_layer(board):
board = str(board).replace(' ', '')
board = board.split('\n')
return [piece_to_num(board[i//8][i%8])/12 for i in range(64)]
for path in glob("C:/Users/Kama/Downloads/Alekhine/*.pgn"):
pgn = open(path)
while True:
game = chess.pgn.read_game(pgn) # reading the game present in file
if game == None:
break
board = chess.Board()
queue = True
count = 0
for move in game.mainline_moves():
board.push(move)
count += 1
if count <= 20:
continue
if queue:
inp = board_to_layer(board)
if queue:
move = str(move)
col = 'abcdefgh'.index(move[0])
row = 8 - int(move[1])
out = [0]*128
out[row*8+col] = 1
col = 'abcdefgh'.index(move[2])
row = 8 - int(move[3])
out[row*8+col + 64] = 1
epoch.append([*inp, out])
queue = not queue
print(epoch[0])
train(epoch, 1000000)
st = shelve.open("chess-weights")
st['weights'] = [W1, W2, W3]
st.close()
print(go_forward(epoch[0][:-1]))
После обучения смотрю - все результаты какие-то нулевые, т.е. на выходе нет ничего, что было бы близко к единице. Поэтому прошу тех, кто этим занимался, посоветовать идею какую-нибудь. Может обучающая выборка слишком большая, но для такой сложной игры необходима огромная выборка. Может быть надо не перцептрон обычный использовать, а какой-то другой тип нейронки.