Из-за характера вопроса, я должен включить много справочной информации (потому что мой вопрос: как мне сузить это?). Тем не менее, это можно обобщить (насколько мне известно) как:
Какие существуют методы поиска локальных оптимумов в чрезвычайно больших комбинаторных пространствах поиска?
Фон
В сообществе суперпользователей с помощью инструментов мы стремимся предоставить специально созданный (не сгенерированный в реальном времени) ввод для игровой консоли или эмулятора, чтобы минимизировать некоторые затраты (обычно время до завершения). В настоящее время это делается путем покадрового воспроизведения игры и указания входных данных для каждого кадра, часто многократно повторяя фрагменты прогона (например, недавно опубликованный прогон «Легенда о Зельде: окарина времени» имеет в общей сложности 198 590 попыток).
Заставление этих трасс достичь своей цели обычно сводится к двум основным факторам: планированию маршрута и обходу. Первый гораздо более «креативный», чем второй.
Планирование маршрута определяет, каким образом игрок должен пройти в целом, чтобы завершить игру, и часто является наиболее важной частью пробега. Это аналогично выбору метода сортировки, например. Лучшая в мире сортировка пузырьков просто не сможет превзойти быструю сортировку по 1 миллиону элементов.
Однако в стремлении к совершенству обход (как проходит маршрут) также является огромным фактором. Продолжая аналогию, мы реализуем алгоритм сортировки. Некоторые маршруты даже не могут быть выполнены без очень определенных кадров ввода. Это самый утомительный процесс вспомогательного инструмента, и это делает производство завершенного цикла продолжительностью в месяцы или даже годы. Это не сложный процесс (для человека), потому что он сводится к тому, чтобы пробовать разные варианты одной и той же идеи, пока человек не будет признан лучшим, но люди могут испытать только столько вариаций своего уровня внимания. Применение машин для решения этой задачи представляется здесь правильным.
Теперь моя цель - попытаться автоматизировать процесс обхода в целом для системы Nintendo 64 . Пространство поиска для этой проблемы пока слишком велико , чтобы атаковать с перебором подходом. Сегмент n-кадра серии N64 имеет 2 30n возможных входов, что означает, что всего 30 кадров ввода (секунда при 30FPS) имеет 2 900 возможных входов; было бы невозможно проверить эти потенциальные решения, не говоря уже о тех, которые рассчитаны на два часа работы.
Тем не менее, я не заинтересован в попытках (а точнее, даже не собираюсь пытаться) полной глобальной оптимизации полного прогона. Скорее, я хотел бы, учитывая начальные данные, приблизить локальный оптимум для определенного сегмента цикла (или ближайших n локальных оптимумов для своего рода полуглобальной оптимизации) . То есть, учитывая маршрут и начальный обход этого маршрута: ищите соседей этого обхода, чтобы минимизировать затраты, но не вырождайтесь в попытки всех случаев, которые могут решить проблему.
Поэтому моя программа должна принимать начальное состояние, входной поток, функцию оценки и выводить локальный оптимум, сводя к минимуму результат оценки.
Текущее состояние
В настоящее время я позаботился обо всех рамках. Это включает в себя оценку входного потока посредством манипуляции с эмулятором, настройкой и разборкой, настройкой и т. Д. И, как своего рода заполнитель, оптимизатор является очень базовым генетическим алгоритмом. Он просто оценивает совокупность входных потоков, сохраняет / заменяет победителя и генерирует новую совокупность, изменяя поток победителя. Этот процесс продолжается до тех пор, пока не будут выполнены некоторые произвольные критерии, такие как время или номер поколения.
Обратите внимание, что самой медленной частью этой программы будет, безусловно, оценка входного потока . Это потому, что это связано с эмуляцией игры для n кадров. (Если бы у меня было время, я бы написал свой собственный эмулятор, который предоставлял хуки для такого рода вещей, но сейчас я остаюсь синтезировать сообщения и изменять память для существующего эмулятора из другого процесса.) На моем главном компьютере, который является довольно современным, оценка 200 кадров занимает примерно 14 секунд. Поэтому я бы предпочел алгоритм (с учетом выбора), который минимизирует количество оценок функций.
Я создал систему в рамках, которая управляет эмуляторами одновременно. Таким образом, я могу оценивать количество потоков одновременно с линейной шкалой производительности, но, на самом деле, количество работающих эмуляторов может быть только от 8 до 32 (а 32 действительно увеличивает его) до того, как производительность системы ухудшится. Это означает (при условии выбора), что алгоритм, который может выполнять обработку во время оценки, будет очень полезным, потому что оптимизатор может выполнять некоторые тяжелые работы, ожидая оценки.
В качестве теста моя функция оценки (для игры Banjo Kazooie ) заключалась в суммировании, на кадр, расстояния от игрока до цели. Это означало, что оптимальным решением было максимально приблизиться к этой точке. Ограничение мутацию только аналогового стика, потребовалось день , чтобы получить ладно решение. (Это было до того, как я реализовал параллелизм.)
После добавления параллелизма я включил мутацию нажатий кнопки «А» и выполнил ту же функцию оценки в области, которая требовала прыжков. С 24 запущенными эмуляторами потребовалось приблизительно 1 час, чтобы достичь цели из изначально пустого потока ввода, но, вероятно, потребуется несколько дней, чтобы достичь чего-то близкого к оптимальному.
проблема
Проблема, с которой я сталкиваюсь, заключается в том, что я недостаточно разбираюсь в области математической оптимизации, чтобы знать, как правильно моделировать мою задачу оптимизации ! Я могу приблизительно следовать концептуальной идее многих алгоритмов, как описано, например, в Википедии, но я не знаю, как классифицировать мою проблему или выбрать современный алгоритм для этой категории.
Из того, что я могу сказать, у меня есть комбинаторная проблема с чрезвычайно большой окрестностью . Кроме того, функция оценки является чрезвычайно прерывистой, не имеет градиента и имеет много плато . Кроме того, здесь не так много ограничений, хотя я с удовольствием добавлю возможность выразить их, если это поможет решить проблему; Я хотел бы разрешить указывать, например, что кнопка «Пуск» не должна использоваться, но это не общий случай.
Вопрос
Итак, мой вопрос: как мне это смоделировать? Какую проблему оптимизации я пытаюсь решить? Какой алгоритм я должен использовать? Я не боюсь читать научные статьи, поэтому дайте мне знать, что я должен читать!
Интуитивно понятно, что генетический алгоритм не может быть лучшим, потому что он, похоже, не учит. Например, если нажатие кнопки «Пуск», кажется, всегда ухудшает оценку (потому что это приостанавливает игру), должен быть какой-то дизайнер или мозг, который учится: «нажимать« Старт »в любой момент бесполезно». Но даже эта цель не так тривиальна, как кажется, потому что иногда нажимающий старт является оптимальным, например, в так называемых «паузах назад-длинные прыжки» в Super Mario 64 ! Здесь мозг должен был бы выучить гораздо более сложный паттерн: «нажимать« Старт »бесполезно, за исключением случаев, когда игрок находится в этом очень специфическом состоянии и продолжит некоторое сочетание нажатий кнопок ».
Кажется, что я должен (или машина может научиться) представлять входные данные каким-то другим способом, более подходящим для модификации. Покадровый ввод кажется слишком гранулированным, потому что на самом деле нужны «действия», которые могут охватывать несколько кадров ... но многие открытия делаются на покадровой основе, поэтому я не могу полностью исключить это ( вышеупомянутая пауза назад-длинный прыжок требует точности на уровне кадра). Также кажется, что факт, что входные данные обрабатываются последовательно, должен быть чем-то, что можно использовать с большой буквы, но я не уверен, как это сделать.
В настоящее время я читаю о (Реактивном) Поиске Табу, Очень широкомасштабном Поиске Соседства, Оптимизации на основе преподавания и обучения и Оптимизации колоний муравьев.
Неужели эта проблема слишком сложна для решения чего-либо, кроме случайных генетических алгоритмов? Или это на самом деле тривиальная проблема, которая была решена давно? Спасибо за чтение и заранее спасибо за любые ответы.