Нейроэволюция — один из самых удобных алгоритмов машинного обучения, с которым можно создавать, настраивать и экспериментировать. В сегодняшней статье мы создадим наш собственный алгоритм нейроэволюции, чтобы научить популяцию автомобилей успешно перемещаться по гоночной трассе.
Мы будем использовать P5.js для графического движка, Tensorflow для обработки наших нейронных сетей и Javascript для объединения всего этого!
Вы можете ознакомиться с проектом, размещенным на Codesphere, здесь: https://38098-3000.codesphere.com/
Давайте прыгать прямо в!
Что такое нейроэволюция?
Нейроэволюция — это метод искусственного интеллекта, который имитирует эволюцию и генетическое воспроизводство для создания «интеллектуальных» моделей, чаще всего в форме искусственных нейронных сетей.
Нейроэволюция чаще всего осуществляется путем создания поколения агентов (в нашем случае автомобилей), которые имеют совершенно случайные веса и предубеждения. Это означает, что они будут эффективно принимать решения случайным образом и, следовательно, не продвинутся далеко.
Затем мы моделируем, как это поколение автомобилей справляется с задачей, которую мы хотим обучить (в данном случае это езда по гоночной трассе).
Затем мы присваиваем каждому автомобилю в поколении оценку того, насколько хорошо он сделан. Вот тут-то и начинается эволюция, потому что мы используем самые результативные автомобили для создания нового поколения.
В частности, нейроэволюция черпает вдохновение из реальных генетических процессов посредством так называемого отбора и мутации.
Селекция — это процесс, посредством которого мы выбираем признаки из родительского поколения. Мутация — это процесс, посредством которого мы случайным образом генерируем признаки для нового поколения.
Нейроэволюция создаст новое поколение посредством отбора и мутации. Как и настоящая эволюция, это имеет тенденцию приводить к тому, что следующее поколение будет немного лучше, чем предыдущее.
Со временем наше количество автомобилей будет становиться все лучше и лучше, пока они не смогут работать на уровне, который нас устраивает.
Наша среда вождения
Я потратил время на предварительную сборку симулятора вождения с помощью P5.js, графической библиотеки Javascript и большого количества декартовой геометрии (Shoutout Desmos).
Если вы хотите, чтобы пустой симулятор вождения следовал за вами, все это содержится в двух файлах, index.html и car.js:
Если вы запустите приведенный выше стартовый код, у вас должно быть первое поколение автомобилей на стартовой линии. Поскольку мы еще не дали им возможности двигаться, все они будут стоять на месте.
Первым шагом в любом алгоритме нейроэволюции является определение входов и выходов, к которым имеет доступ ваш вид. В нашем случае каждый автомобиль может определить, насколько близко находится объект в каждом из 5 направлений (обозначено красными линиями). Он получит число от 1 до 20, представляющее, насколько близко находится объект. Если объекта нет, они также получат 20.
С точки зрения выхода каждая машина может принять четыре решения:
- Ускорить
- Тормоз
- Поверните направо
- Поверните налево
Конечно, если машина врежется в стену или препятствие, она погибнет.
Показатель пригодности автомобиля (насколько он хорош) определяется тем, сколько кругов он проехал (по 100 каждый) плюс расстояние по трассе (от 0 до 100). Например, если машина проедет 2 с половиной круга, прежде чем заглохнет, ее приспособленность будет равна 250.
Создание нашей нейронной сети с помощью Tensorflow
Теперь давайте дадим каждой машине возможность принимать решения о вождении. Мы будем снабжать каждый автомобильный объект искусственной нейронной сетью, которая принимает 5 целых чисел, представляющих близость к препятствию в каждом направлении. Тогда у нас будет один скрытый слой из 8 нейронов с активациями ReLU. Наконец, нейронная сеть выдаст 4 значения для каждого решения, которое она может принять:
- Ускорить
- Тормоз
- Поверните направо
- Поверните налево
Выходной слой будет использовать сигмовидную функцию активации, которая будет давать нам значения от 0 до 1 для каждого решения. Затем машина будет умножать каждое решение на максимальную скорость, с которой она может выполнять действие.
Например, предположим, что мы позволяем каждому автомобилю разгоняться с максимальным ускорением 0,50. Если он выводит 0,20 для первого нейрона, то мы добавим к скорости 0,2 * 0,5 (таким образом, 0,1).
Давайте сначала создадим модель в классе Car:
Обязательно вызовите указанную выше функцию в конструкторе класса Car.
Затем, прежде чем мы обновим положение каждого класса автомобиля в нашей функции рисования, давайте соберем входные данные и используем эту модель для принятия решений для автомобиля:
Теперь наши автомобили могут принимать решения, но имейте в виду, что веса и смещения наших нейронных сетей совершенно случайны. Таким образом, автомобили, скорее всего, будут заниматься ерундой:
На самом деле многие наши машины просто бесцельно крутятся кругами или вообще ничего не делают. Не о чем беспокоиться, поскольку все, что нам нужно, это случайно решить двигаться вперед, чтобы наша эволюция шла в правильном направлении!
Генетическая селекция и разведение новых поколений
Следующим шагом является разведение нового поколения. Мы будем использовать то, что известно как Пропорциональный фитнес, или Колесо рулетки, Выбор.
Этот алгоритм работает, рассматривая показатели пригодности каждого автомобиля в родительском поколении и случайным образом выбирая черты всех родителей, так что наиболее эффективные родители имеют наибольшую вероятность передачи своих черт.
Чтобы вычислить это, мы возьмем сумму оценок пригодности каждого автомобиля и используем функцию кумулятивного распределения, чтобы выбрать автомобиль. Если вам нужно более подробное объяснение математики здесь, свяжитесь с нами, и мы будем рады объяснить более подробно.
Кроме того, давайте создадим функцию, которая будет вычислять общую пригодность в конце поколения, а также вычислять наивысшую пригодность в поколении для целей сравнительного анализа (позже мы будем использовать метку, чтобы показать наивысший балл и текущее поколение).
Последняя вспомогательная функция, которая нам нужна, — это способ скопировать вес каждой машины, чтобы мы могли передать его новым поколениям:
Теперь давайте напишем нашу функцию для создания нового поколения.
Для каждого нового потомка мы будем перебирать вес в его модели и случайным образом назначать ему вес от родителя (используя наш алгоритм выбора).
Наконец, давайте запустим это новое поколение всякий раз, когда каждая машина неактивна, или по прошествии определенного времени.
Давайте создадим в нашем index.html целое число с именем frameCount, чтобы отслеживать, как долго длится поколение. Затем добавим следующий код в конец нашей функции рисования:
Теперь, если все реализовано правильно, мы можем начать видеть некоторый прогресс в течение пары поколений:
Но также невероятно вероятно, что вы можете увидеть что-то вроде этого:
Это связано с тем, что черты поколения полностью определяются чертами их родителей. Это означает, что если вы сможете создать особенно ужасное поколение, вы продолжите получать ужасных детей и застрянете в бесконечной петле.
Вот где в дело вступает мутация.
Генетическая мутация
Мутация — это когда определенному весу присваивается случайное значение. Вероятность мутации веса, а не выбора от родителя, является нашей частотой мутаций.
Мы возьмем нашу частоту мутаций из созданного нами текстового поля и обновим нашу новую функцию генерации следующим образом:
Это позволит поколениям иметь подстановочные черты и подняться над конкурентами.
Теперь мы должны увидеть значительный прогресс поколений:
Таким образом, мутация позволяет нашим машинам экспериментировать с новыми стратегиями, а отбор позволяет хорошим стратегиям распространяться среди населения.
Спустя всего 50 поколений у нас есть большинство наших автомобилей, способных преодолевать круги.
Окончательный код
Что дальше
Если вы действительно хотите бросить себе вызов, поиграйте с препятствиями. Мы специально сделали это так, чтобы вы могли очень легко пройти более сложную трассу.
Кроме того, есть всевозможные алгоритмы, которые вы можете использовать для мутации и отбора, играя с ними, вы сможете улучшить производительность алгоритмов нейроэволюции!
Это все от нас сегодня, и помните
Живая демонстрация (развернута на Codesphere): https://38098-3000.codesphere.com/
Есть вопросы? Оставьте их ниже, и мы будем рады помочь.
Как всегда удачного кодинга от команды Codesphere. Мы создаем Web IDE, работающую в облачной инфраструктуре, чтобы ваши возможности по созданию и развертыванию программного обеспечения никогда не ограничивались вашим локальным компьютером.