шахматная нейросеть на 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]))

После обучения смотрю - все результаты какие-то нулевые, т.е. на выходе нет ничего, что было бы близко к единице. Поэтому прошу тех, кто этим занимался, посоветовать идею какую-нибудь. Может обучающая выборка слишком большая, но для такой сложной игры необходима огромная выборка. Может быть надо не перцептрон обычный использовать, а какой-то другой тип нейронки.


Ответы (0 шт):