From 89115aa0e5d44b9cbe9d42e82fc58ce68bb1cb46 Mon Sep 17 00:00:00 2001 From: shai bentov Date: Sun, 19 May 2019 18:11:03 -0700 Subject: [PATCH] make it easier to choose backend / algo --- engine.py | 133 +++++++++++++++++++++----------------------------- leela_lite.py | 110 ++++++++++++++++++++++------------------- 2 files changed, 115 insertions(+), 128 deletions(-) diff --git a/engine.py b/engine.py index 8e21cc1..6ebb1fc 100644 --- a/engine.py +++ b/engine.py @@ -1,9 +1,9 @@ -from lcztools import load_network, LeelaBoard +from lcztools import LeelaBoard, list_backends import search -import chess -import chess.pgn import sys +from leela_lite import get_search_algos + logfile = open("leelalite.log", "w") LOG = False @@ -40,77 +40,56 @@ def process_position(tokens): return board -if len(sys.argv) == 3: - weights = sys.argv[1] - nodes = int(sys.argv[2]) - type = "uct" -elif len(sys.argv) == 4: - weights = sys.argv[1] - nodes = int(sys.argv[2]) - if sys.argv[3] == 'minimax': - type = 'minimax' - else: - type = 'uct' -else: - print("Usage: python3 engine.py ") - print(len(sys.argv)) - exit(1) - -network_id = None -try: - # If the parameter is an integer, assume it's a network server ID - network_id = int(weights) - weights = None -except: - pass - -def load_leela_network(): - global net, nn - if network_id is not None: - net = load_network(backend='net_client', network_id=network_id, policy_softmax_temp=2.2) - else: - net = load_network(backend='pytorch_cuda', filename=weights, policy_softmax_temp=2.2) - nn = search.NeuralNet(net=net, lru_size=max(5000, nodes)) - - -send("Leela Lite") -board = LeelaBoard() -net = None -nn = None - - - -while True: - line = sys.stdin.readline() - line = line.rstrip() - log("<{}".format(line)) - tokens = line.split() - if len(tokens) == 0: - continue - - if tokens[0] == "uci": - send('id name Leela Lite') - send('id author Dietrich Kappe') - send('uciok') - elif tokens[0] == "quit": - exit(0) - elif tokens[0] == "isready": - load_leela_network() - send("readyok") - elif tokens[0] == "ucinewgame": - board = LeelaBoard() - elif tokens[0] == 'position': - board = process_position(tokens) - elif tokens[0] == 'go': - my_nodes = nodes - if (len(tokens) == 3) and (tokens[1] == 'nodes'): - my_nodes = int(tokens[2]) - if nn == None: - load_leela_network() - if type == 'uct': - best, node = search.UCT_search(board, my_nodes, net=nn, C=3.0) - else: - best, node = search.MinMax_search(board, my_nodes, net=nn, C=3.0) - send("bestmove {}".format(best)) - -logfile.close() +def uci(args): + from leela_lite import load_leela_network + + send("Leela Lite") + board = LeelaBoard() + + nodes = args.nodes + net = load_leela_network(args.weights, args.backend) + nn = search.NeuralNet(net=net, lru_size=min(5000, nodes)) + + search_func = get_search_algos()[args.algo] + + while True: + line = sys.stdin.readline() + line = line.rstrip() + log("<{}".format(line)) + tokens = line.split() + if len(tokens) == 0: + continue + + if tokens[0] == "uci": + send('id name Leela Lite') + send('id author Dietrich Kappe') + send('uciok') + elif tokens[0] == "quit": + exit(0) + elif tokens[0] == "isready": + send("readyok") + elif tokens[0] == "ucinewgame": + board = LeelaBoard() + elif tokens[0] == 'position': + board = process_position(tokens) + elif tokens[0] == 'go': + my_nodes = nodes + if (len(tokens) == 3) and (tokens[1] == 'nodes'): + my_nodes = int(tokens[2]) + best, node = search_func(board, my_nodes, net=nn, C=3.0) + send("bestmove {}".format(best)) + + logfile.close() + +if __name__ == '__main__': + algos = get_search_algos().keys() + + import argparse + parser = argparse.ArgumentParser(description='') + parser.add_argument('weights', help='weights file or network server ID') + parser.add_argument('nodes', type=int, help='nodes per move') + parser.add_argument('-a', '--algo', default='uct', help='search algo to use', choices=algos) + parser.add_argument('-b', '--backend', default='pytorch_cuda', choices=list_backends(), help='nn backend') + + args = parser.parse_args() + uci(args) diff --git a/leela_lite.py b/leela_lite.py index 0a311be..f29d171 100644 --- a/leela_lite.py +++ b/leela_lite.py @@ -1,5 +1,5 @@ #!/usr/bin/python3 -from lcztools import load_network, LeelaBoard +from lcztools import load_network, LeelaBoard, list_backends import search import chess import chess.pgn @@ -7,60 +7,68 @@ import time -if len(sys.argv) != 3: - print("Usage: python3 leela_lite.py ") - print(len(sys.argv)) - exit(1) -else: - weights = sys.argv[1] - nodes = int(sys.argv[2]) +def load_leela_network(weights, backend): + if backend == 'net_client': + network_id = int(weights) + return load_network(backend='net_client', network_id=network_id, policy_softmax_temp=2.2) -network_id = None -try: - # If the parameter is an integer, assume it's a network server ID - network_id = int(weights) - weights = None -except: - pass + return load_network(backend=backend, filename=weights, policy_softmax_temp=2.2) -def load_leela_network(): - global net, nn - if network_id is not None: - net = load_network(backend='net_client', network_id=network_id, policy_softmax_temp=2.2) - else: - net = load_network(backend='pytorch_cuda', filename=weights, policy_softmax_temp=2.2) +def get_search_algos(): + from inspect import getmembers, isfunction + + methods = {} + for key, value in getmembers(search, isfunction): + if key.endswith('_search'): + methods[key.rsplit('_',1)[0].lower()] = value + return methods + +def play(args): + nodes = args.nodes + net = load_leela_network(args.weights, args.backend) nn = search.NeuralNet(net=net, lru_size=min(5000, nodes)) - -load_leela_network() + search_func = get_search_algos()[args.algo] -SELFPLAY = True + SELFPLAY = True -board = LeelaBoard() -while True: - if not SELFPLAY: - print(board.unicode()) - print("Enter move: ", end='') - sys.stdout.flush() - line = sys.stdin.readline() - line = line.rstrip() - board.push_uci(line) - print(board.unicode()) - print("thinking...") - start = time.time() - best, node = search.UCT_search(board, nodes, net=nn, C=3.4) - elapsed = time.time() - start - print("best: ", best) - print("Time: {:.3f} nps".format(nodes/elapsed)) - print(nn.evaluate.cache_info()) - board.push_uci(best) - if board.pc_board.is_game_over() or board.is_draw(): - result = board.pc_board.result(claim_draw=True) - print("Game over... result is {}".format(result)) + board = LeelaBoard() + while True: + if not SELFPLAY: + print(board.unicode()) + print("Enter move: ", end='') + sys.stdout.flush() + line = sys.stdin.readline() + line = line.rstrip() + board.push_uci(line) print(board.unicode()) - print() - pgn_game = chess.pgn.Game.from_board(board.pc_board) - pgn_game.headers['Result'] = result - print(pgn_game) - break - + print("thinking...") + start = time.time() + best, node = search_func(board, nodes, net=nn, C=3.4) + elapsed = time.time() - start + print("best: ", best) + print("Time: {:.3f} nps".format(nodes/elapsed)) + print(nn.evaluate.cache_info()) + board.push_uci(best) + if board.pc_board.is_game_over() or board.is_draw(): + result = board.pc_board.result(claim_draw=True) + print("Game over... result is {}".format(result)) + print(board.unicode()) + print() + pgn_game = chess.pgn.Game.from_board(board.pc_board) + pgn_game.headers['Result'] = result + print(pgn_game) + break + +if __name__ == '__main__': + algos = get_search_algos().keys() + + import argparse + parser = argparse.ArgumentParser(description='') + parser.add_argument('weights', help='weights file or network server ID') + parser.add_argument('nodes', type=int, help='nodes per move') + parser.add_argument('-a', '--algo', default='uct', help='search algo to use', choices=algos) + parser.add_argument('-b', '--backend', default='pytorch_cuda', choices=list_backends(), help='nn backend') + + args = parser.parse_args() + play(args)