Со времени прошлого поста я изменил технологии программирования и добавил несколько фич в модель, таких как ДНК.
Теперь вместо CPython + GTK я использую IronPython + WPF. Выбор в первую очередь был основан на том, что в IronPython реализуется действительная многопоточность, и при работе с этим интерпритатором очень удобно работать с gui.
Ну да не будем заморачиваться технологическими вопросами и перейдём к главному.
Описание модели
На 2D-поле имеются агенты (зеленые и красные) и пища (серая) (см. рис. 2.1).
Рис. 2.1 Общий вид
Агент способны перемещаться вперед\назад относительно текущего угла поворота и изменять его, т.е. поворачиваться по или против часовой стрелки. А значит, его действие в конкретный момент времени можно выразить в виде вектора в полярной системе координат.
На окружности агента расположены сенсоры, которыми тот способен воспринимать запах, исходящий от пищи (см. рис. 2.2). Чем дальше пища - тем слабее будет запах. Зависимость от расстояния линейное.
Рис. 2.2 Запах пищи
У каждого агента имеется простая искусственная нейронная сеть (перцептрон) с тремя слоями и количеством нейронов входного слоя равным количеству сенсоров (в моём случае 7), двумя нейронами в скрытом слое, и двумя нейронами в выходном слое. Первый нейрон выходного слоя даёт величину передвижения вперед\назад, второй нейрон - величину угла поворота.
Количество нейронов в скрытом слое было выведено экспериментально. Для этого, сперва, был создан приемлемый алгоритм, который бы обеспечивал эффективный поиск и достижение пищи агентом (в последствии эволюционировавшие агенты превзошли этот, наспех набросанный алгоритм). После, перебирались различные структуры перцептрона, и тот проверялся на способность повторить заданный алгоритм. Двух нейронов оказалось достаточно.
Каждый агент обладает энергией, которая пополняется, если тот стоит достаточно близко около пищи. При этом пища уменьшается, пропорционально съеденному, пока вовсе не исчезнет. А расходуется энергия на: передвижение, размножение и просто на существование. Если энергия у особи кончается, то она умирает. Если же, наоборот, энергии достаточно много (более 70%), то особь становится “половозрелой” и у неё появляется шанс на размножение. Принцип размножения будет описан немного позднее.
Пища лежит себе да пахнет. Важен способ её формирования. Она равномерно добавляется в случайное место поля, через одинаковые промежутки времени. Таким образом достигаются необходимые условия для осуществления естественного отбора:
Когда популяция агентов мала, пища накапливается, создавая благоприятные условия для выживания и размножения. Особи размножаются, популяция растёт, но, затем, пища кончается и большая популяция остаётся в суровых условиях. Тут вступает в силу естественный отбор, который дефицитом пищи “убивает” наименее приспособленных или наименее везучих особей. Популяция вновь становится малой и цикл повторяется.
Важно понимать, что это не часть программы, а закономерность, которая наблюдается в процессе моделирования. Под естественным отбором я понимаю то, что из-за нехватки пищи у многих особей кончается энергия и они умирают. А те, у которых нейронная сеть способна в большей степени реагировать на запах пищи и, своими действиями, так или иначе приближать агента к ней, получают больше шансов выжить.
Размножение происходит половым путем, т.е. для образования потомства необходимо две половозрелые особи. Агенты могут иметь мужской или женский пол. Разделение особой по полам было сделано лишь по той причине, что это было проще реализовать в многопоточной среде, в то же время не значительно сказывалось на результатах моделирования.
Когда две половозрелые особи разных полов подходят достаточно близко друг к другу, у них появляется шанс создать потомство (2-4 особи), при этом отдав им часть своей энергии.
Образование потомства. У каждой особи есть ДНК, в которой содержится информация о поле особи и о каждой весе его нейронной сети. ДНК в данной модели представляет собой символьную последовательность, элемент которой может принимать четыре значение: 0,1,2,3. Для описания пола используется первый символ. Если цифра четная, то особь женского пола, иначе - мужского. Для каждого веса нейрона, значения которого расположены в отрезке [-1;1], используется 5 символов. Если представить эти 5 символов как пятизначное число с основанием 4, то оно содержит 45 = 1024 вариантов чисел. И, если разбить отрезок [-1;1] на 1024 части, то мы сможем описать любое число на нём с точностью до 21024=0.001953125. Что даёт вполне приемлемую дискретизацию для весов нейронной сети.
Итак, если нейронная сеть имеет три слоя в которых соответственно 7, 2 и 2 нейрона, то длинна ДНК описывающего нейронную сеть будет составлять (2*(7+1) + 2*(2+1)) * 5 = 110 символов. Итоговая длина ДНК особи равна 111, где еще один символ занимает описание пола.
ДНК новой особи формируется из родительских, проходя два этапа:
- С двумя ДНК родителей происходит кроссинговер, в результате которого, образуется две новых ДНК.
Вкратце кроссинговер (см. рис. 2.3) можно описать как процесс, при котором обе ДНК родителей разделяются в случайном месте и обмениваются своими конечностями так, что в результате появляется две новых ДНК такой же длинны.
Рис. 2.3 Кроссинговер
Для следующего этапа выбирается одна случайная из них.
- С полученной ДНК происходит мутация: каждый символ ДНК с некоторой долей вероятности (в моём случае 0.05) может изменить своё значение на любое другое или на тоже самое (см. рис. 2.4).
Рис. 2.4 Мутация
ЗАКЛЮЧЕНИЕ
С полученой моделью мы наблюдаем усточивую эволюцию поведения агентов. Начиная с момента, когда на поле инициализируется 20 агентов со случайным ДНК, развитие, как упоминалось ранее, происходит циклически: чередуются дифицит и изобилие пищи. Во время изобилия особи размножаются, скрещивая свои ДНК и подготавливая базу для последующего естественного отбора. Во время дифицита пищи преимущество у более приспособленных.
Сначала, амплитуда численности большая, но по мере того, как особи становятся более обученными и способными к выживанию, она уменьшается.Ну и конечно ссылка на репозиторий с кодом: https://github.com/zshimanchik/iron-unconditioned-reflexes
И видосик:
Захар, а что изменится если "запах" сделать нелинейным, а с квадратичной зависимостью? Суть такая, что запах -- это молекула и сила запаха -- это количество молекул на объем (в твоем случае -- площадь). т.е. тот кто ближе будет чувствовать запах сильнее.
ReplyDeleteСделал зависимость силы запаха от расстояния квадратичным и несколько раз протестировал. Особо ничего не изменилось, кроме максимального расстояния, на котором они начинали реагировать - оно стало поменьше.
DeleteТеоритически это могло увеличить разность значений на сенсорах у агента, т.е. те сенсоры что ближе к пище сигнализировали бы об этом сильнее, чем при "линейности" запаха, и, тем самым, нейронной сети было бы легче выделить ключевые стимулы. Однако, если это и произошло, то в малой степени и незаметно.
А вообще, замечание классное и я оставил эти изменения.