идти бот с минимаксным деревом поиск слишком медленно - PullRequest
1 голос
/ 19 сентября 2019

Я читаю книгу «глубокое обучение и игра в го», и я не зашел далеко в этой книге;Я написал основы (правила, вспомогательные классы) и графический интерфейс Qt.Все работает, и я решил написать примеры минимаксной программы, чтобы посмотреть, смогу ли я победить ее ;-), но она слишком медленная: требуется несколько минут, чтобы разыграть один ход с исходной доской 9x9.С глубиной по умолчанию в 3 хода, я думаю, что вычисление первого хода заняло бы (9x9) x (9x9-1) x (9x9-2) ~ 500 000 позиций.Хорошо, это Python, а не C, но я думаю, что это можно вычислить максимум за одну минуту.

Я удалил один вызов метода copy.deepcopy (), который, казалось, занимал много времени.Но он остается слишком медленным.

Вот некоторые вещи: вычислительный поток:

class BotPlay(QThread):
    """
    Thread de calcul du prochain coup par le bot
    """

    def __init__(self, bot, bots, game):
        """
        constructeur, pour le prochain coup à jouer

        :param bot: le bot qui doit jouer
        :param bots: l'ensemble des 2
        :param game: l'état actuel du jeu (avant le coup à jouer)
        """
        QThread.__init__(self)
        self.bot = bot
        self.bots = bots
        self.game = game

    played = pyqtSignal(Move, dict, GameState)

    def __del__(self):
        self.wait()

    def run(self):
        self.msleep(300)
        bot_move = self.bot.select_move(self.game)
        self.played.emit(bot_move, self.bots, self.game)

метод select move и его класс:

class DepthPrunedMinimaxAgent(Agent):

    @bot_thinking(associated_name="minimax prof. -> LONG")
    def select_move(self, game_state: GameState):
        PonderedMove = namedtuple('PonderedMove', 'move outcome')
        best_move_so_far = None
        for possible_move in game_state.legal_moves():
            next_state = game_state.apply_move(possible_move)
            our_best_outcome = -1 * self.best_result(next_state, capture_diff)
            if best_move_so_far is None or our_best_outcome > best_move_so_far.outcome:
                best_move_so_far = PonderedMove(possible_move, our_best_outcome)
        return best_move_so_far.move

    def best_result(self, game_state: GameState, eval_fn, max_depth: int = 2):
        if game_state.is_over():
            if game_state.next_player == game_state.winner():
                return sys.maxsize
            else:
                return -sys.maxsize

        if max_depth == 0:
            return eval_fn(game_state)

        best_so_far = -sys.maxsize
        for candidate_move in game_state.legal_moves():
            next_state = game_state.apply_move(candidate_move)
            opponent_best_result = self.best_result(next_state, eval_fn, max_depth - 1)
            our_result = -opponent_best_result
            if our_result > best_so_far:
                best_so_far = our_result
        return best_so_far

Я почтиуверен, что проблема не в графическом интерфейсе, потому что начальная версия программы, заданная книгой, и полностью в режиме консоли, такая же медленная, как моя.

Что такое мой запрос?Ну, чтобы быть уверенным, что это медленное поведение не нормально, и, возможно, иметь представление о том, что идет не так.Минимаксный алгоритм взят из книги, так что все в порядке.

спасибо

Ответы [ 2 ]

2 голосов
/ 19 сентября 2019

Может быть сложно написать эффективный (быстрый) код поиска на Python.Но, если вы хотите использовать Python, первое / главное, о чем нужно беспокоиться, это избегать выделения памяти.Попробуйте предварительно выделить любую память, которая будет использоваться.Второе, о чем нужно беспокоиться, это ненужное копирование - убедитесь, что вы не копируете данные без необходимости.Эти два изменения, которые могут быть непростыми для применения, будут иметь большое значение для ускорения вашего кода.

Их легче контролировать в таких языках, как C или C ++, но все же можно сделать в Python.По моему опыту, основанная на поиске программа, написанная плохо (с выделением памяти и ненужным копированием) на Python, может быть в 100 раз или даже в 1000 раз медленнее, чем хорошо написанная программа на C / C ++.

Кстати, Monte-Carlo Tree Search (MCTS) является преобладающим подходом в Go в эти дни, поэтому вы можете захотеть взглянуть на MCTS.Но в любом случае вам нужно, чтобы ваш код работал быстрее, чтобы он работал хорошо.

2 голосов
/ 19 сентября 2019

Машинное обучение часто выполняется на Python, потому что:

    1. это просто и безопасно
  • Гибко
  • все тяжелые операции выполняются в специализированном модуле, например, tenorflow и keras

В вашем случае 3. не выполняется.Все эти гнездовые вызовы, передача параметров, копирование и оценка платы выполняются в Python.Это обходится вам в 10-100 раз дороже, чем на скомпилированном языке [цитата нужна].

Похоже, что популярный проект ML сделан на Python, но реальный код Python заключается только в обработке и подаче данных, контролевызовы tenorflow и отображение результатов.Вот почему они могли это сделать.

Так что, да, ничего необычного в вашей истории.Ты смотрел на Лилу-ноль?Это намного сложнее / сложнее, но с открытым исходным кодом и очень хорошо сделано, и, вероятно, уже побеждает.

...