Вы находитесь на странице: 1из 12

I. Эволюция машин.

Введение в генетическое
программирование.

1. Эволюционные вычисления

Существует метод решения задач, заимствованный из биологии. Это


эволюция – создание поколений потомков, которое лучше своих родителей.
Здесь мы рассмотрим, как можно использовать процесс, схожий с процессом
эволюции, для создания полезных программ.

В биологии эволюция происходит при появлении новых потомков,


отличающихся от родителей, и при селективном выживании этих потомков с
целью создания новых потомков. Этих двух аспектов – изменение в процессе
воспроизведения и селективное выживание – достаточно для создания новых
поколений индивидов, которые все лучше и лучше выполняют все, что
необходимо для их выживания.

В качестве иллюстрации рассмотрим геометрическую аналогию,


изображающую упрощенную версию процесса: представим математический
«ландшафт» из гор, долин и равнин, населенный популяцией из нескольких
индивидов, расположенных в произвольных точках ландшафта. Высота
индивида на ландшафте показывает, насколько лучше он выполняет свою
задачу относительно других. Те индивиды, которые находятся на нижних
уровнях, прекращают существовать, с вероятностью, которая растет с
уменьшением высоты. Индивиды на высоких уровнях «воспроизводятся» с
вероятностью, которая растет при росте высоты. Воспроизведение включает
в себя создание новых индивидов, чье расположение на ландшафте зависит
от родителей, но при этом отличается. Самый интересный и эффективный
вид воспроизведения касается создания новых индивидов одновременно
двумя родителями. Положение потомка на ландшафте – это функция от
положения родителей. В некоторых реализациях эволюционного процесса,
положение потомка – это в некотором роде что-то «средние» между
положением родителей.

Мы можем рассматривать этот процесс как поиск наивысшей точки на


ландшафте. Новые индивиды занимают новые территории, и те, которые
находятся на нижних уровнях, умирают. Через некоторое время, какие-
нибудь индивиды доберутся до вершины. Эффективность процесса зависит
от того, чем индивиды отличаются от своих родителей и от природы
ландшафта.
Процесс эволюционного поиска используется в информатике в двух
основных направления. Самое прямое применение – оптимизация функций.
Например, мы пытаемся найти максимум функции f(x1, …, xn). Аргументы
(x1, …, xn) определяют положение индивида, а значение f – высота.
Холланд (Holland, [1975]) предложил класс Генетических Алгоритмов (ГА)
для решения подобных задач.

Другое применение – развивать компьютерные программы для решения


конкретных задач. Например, задача управления агентом. Такое
использование эволюции мы и будем рассматривать. Для этой цели подходит
расширение ГА, так называемая система классификаторов (classifier system),
предложенное John Holland (Система классификаторов – это основанная на
синтаксически простых правилах (классификаторов) самообучающаяся
система, впервые предложенная Холландом [Holland, 1975]). Другой метод,
называемый Генетическим Программированием (ГП), развивает программы в
более явной форме, нежели ГА. В следующем разделе на конкретном
примере будет описан процесс ГП.

2. Генетическое программирование

2.1. Представление программ в генетическом


программировании
В ГП мы будем работать с функциональными программами, такими как
функции LISP. Такие программы могут быть представлены, как дерево с
корнем и помеченными вершинами. Внутренние узлы – функции, предикаты
или действия от одного или более аргументов. Листья – программные
константы, действуя или функции без аргументов. Для примера, рассмотрим
программу 3 + (5 * 4)/7, записанную в виде дерева (рисунок 1). В этом
случае, листья – это константы 2, 4, 5 и 7, а внутренние узлы – функции +,
*, /.

Рисунок 1. Представление программы в


виде дерева.
Рассмотрим работу ГП на примере задачи о гуляющем роботе. Предположим,
что мир робота – это двумерное клеточное пространство (рисунок 2). Мы
хотим построить программу так, чтобы она принимала на вход показания
сенсоров робота, а на выходе выдавала бы действие робота. Робот
управляется постоянным выполнением этой программы. И мы хотим, чтобы
робот, начиная движение в произвольной клетке пространства, двигался по
направлению к стене и продолжал постоянно ходить вдоль нее.

Рисунок 2. Робот в клеточном мире.

Примитивные функции, которые будут использоваться в программе,


включают в себя булевские функции AND, OR, NOT и функцию IF; и
четыре функции действий north, east, south и west. Булевские функции
имеют следующее определение:

1. (AND x y)=0 если x=0; в противном случае y;

2. (OR x y)=1 если x=1; в противном случае y;

3. (NOT x)=0 если x=1; в противном случае 1;

4. (IF x y z)=y если x=1; в противном случае z.

Функции действий определяются так:

1. north – двигает робота на одну клетку вверх;

2. east – двигает робота на клетку вправо;

3. south – двигает робота на клетку вниз;

4. west – двигает робота на клетку влево.


Функции действий не возвращают никаких значений; вычисление любой из
них приводит к останову программы, таким образом, нет нужды возвращать
значение. Все функции действия работают по своим указанным свойствам,
пока робот не попытается пройти сквозь стену; в этом случае, ничего не
происходит и программа завершает работу. В этом случае многократное
повторение программы также не будет иметь эффекта.

В качестве сенсоров будем использовать n, ne, e, se, s, sw, w и nw (они


изображены на рисунке 2). Эти сенсоры будут выдавать 0, если
соответствующая ячейка свободна, иначе она вернет 1.

В ГП мы должны быть уверены, что все выражения и подвыражения,


используемые в программе, имеют значения для всех возможных аргументов.
Например, если мы используем функцию Divides(x, y), означающую
деления x на y, мы должны всегда возвращать значение, даже когда y = 0.
Таким образом, мы будем знать, что любое дерево, построенное так, чтобы
удовлетворять данному свойству, будет описывать допустимую программу.
Дальше будет показано, почему важно выполнение этого свойства.

Прежде чем приступать к применению ГП для задачи о гуляющем роботе,


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

Рисунок 3. Программа гуляющего робота.


(IF (AND (OR (n) (ne)) (NOT (e)))

(east)

(IF (AND (OR (e) (se)) (NOT (s)))

(south)

(IF (AND (OR (s) (sw)) (NOT (w)))

(west)

(north))))

2.2. Процесс генетического программирования


Генетическое программирование начинается с популяции произвольно
созданных программ, состоящих из функций, констант и показаний сенсоров,
необходимых для построения эффективного решения поставленной задачи.
Эти начальные программы составляют нулевое поколение. Размер нулевого
поколения – один из основных параметров работы ГП. В нашем примере
процесса ГП, мы будем начинать с популяции из 5000 произвольных
программ, и пытаться вывести программу гуляющего робота. Мы составляем
эти начальные программы из примитивных функций AND, OR, NOT и IF,
действий north, east, south и west, сенсорных функций n, ne, e, se, s,
sw, w, nw, и констант 0 и 1. Программы в каждом поколении вычисляются,
и создается новое поколение, исходя из того, насколько хорошо подходят
данные программы.

Чтобы посмотреть насколько хорошо программа подходит для решения


поставленной задачи, она запускается. В нашем случае, мы будем запускать
программу 60 раз, и считать, сколько ячеек вдоль стены мы посетили за эти
60 шагов. (Всего 32 ячейки находятся у стены, поэтому программа, которая
никогда не доберется до стены, наберет 0 ячеек, а идеальная программа
соберет все 32). Затем мы совершаем 10 прогонов робота, при этом каждый
раз начинаем в произвольно выбранной клетке на поле. Общее число
посещенных за десять прогонов соседних со стеной ячеек берется как
значение приспособленности (fitness) программы. Максимально возможное
значение приспособленности – 320, оно достигается только тогда, когда
робот на каждом из 10 прогонов посетит все соседние со стеной ячейки за 60
шагов.

Поколение (i + 1) получается из поколения i следующим способом:


1. 500 программ (10%) из поколения i копируются в поколение i + 1.
Кандидаты на копирование выбираются с помощью «турнира»: семь
программ произвольно выбираются из поколения. Затем остается самый
приспособленный (с наибольшим значением меры приспособленности)
индивид. («Турнир» – один из эффективных методов выбора хорошо
приспособленного индивида. Число 7 и процент программ, переносимых в
новое поколение, – дополнительные параметры процесса ГП.)

2. 4500 новых программ (90%) добавляются в поколение i + 1. Каждая


новая программа получается из программ «мамы» и «папы» с помощью
операции скрещивания: мама и папа выбираются из поколения i
посредством «турнира». Затем произвольно выбранное поддерево
программы «отца» замещается произвольно выбранным поддеревом
программы «матери». Результат – программа «потомок». (Корректность
программы потомка обеспечивается требованием того, чтобы все
используемые функции корректно работали со всеми возможными
значениями аргументов). Этот процесс изображен на рисунке 4.
Закрашенные узлы, обозначают произвольно выбранные поддеревья
родителей. Программа потомка может быть, а может не быть более
приспособленной, чем ее родители. Мотивация возможной эффективности
операции скрещивания заключается в том, что основная программа и
основное подвыражение родителей содержится в их потомке.

3. Иногда при создании индивидов для нового поколения также


используется операция мутации (обычно не значительно, около 1%
программ). Операция мутации выбирает одного родителя из поколения с
помощью «турнира». Произвольно выбранное поддерево удаляется из
этого родителя и заменяется новым выращенным поддеревом (созданным
тем же способом, что и начальные программы в нулевом поколении). В
нашем примере эта операция не использовалась.
Рисунок 4. Программы родителей и их потомок.

Заметим, что некоторые, довольно произвольные параметры должны быть


заданы при создании нового поколения. Сюда входят число индивидов для
переноса в новое поколение, число индивидов получаемых с помощью
операции скрещивания, число программ участвующих в соревновании, и
процент для операции мутации. Выбор параметров, используемых в нашем
примере, основан на изучении и поиске наиболее оптимальных значений
параметров ГП.

2.3. Обучение гуляющего робота


Мы начинаем с поколения из 5000 произвольно созданных программ, и
применяем описанный метод для запуска процесса ГП для обучения
гуляющего робота. Многие программы нулевого поколения вообще ничего
не делают: например, программа (AND (sw) (ne)) вычисляет первый
элемент и останавливается, если он 0, иначе вычисляет второй аргумент, и
останавливается (ее значение пригодности равно 0). Некоторые программы
передвигаются только в одном направлении независимо от входных данных.
Например, когда программа (OR (e) (west)) вычисляет west, она двигается
на запад и останавливается. Эта программа набрала 5 очков
приспособленности (во время прогонов она случайно оказалась у стены).

Списочная структура наиболее приспособленной программы нулевого


поколения (набравшая число 92) и два ее прогона представлены на рисунке 5.
Как обычно в ГП, программа трудно читаема и имеет много лишних
операций. (Некоторые недостатки могут быть удалены с помощью
специального транслятора.) Начиная в произвольной ячейки, эта программа
идет на восток, пока не дойдет до ячейки у стены; затем она двигается на
север, пока не сможет снова пойти на восток, или идет на запад и застревает
в верхней левой ячейке.

Рисунок 5. Наилучшая программа в поколении 0.

(AND (NOT (NOT (IF (IF (NOT (nw))

(IF (e) (north) (east))

(IF (west) (0) (south)))

(OR (IF (nw) (ne) (w))

(NOT (sw)))

(NOT (NOT (north))))))

(IF (OR (NOT (AND (IF (sw) (north)


(ne))

(AND (south) (1))))

(OR (OR (NOT (s))

(OR (e) (e)))

(AND (IF (west) (ne) (se))

(IF (1) (e) (e)))))

(OR (NOT (AND (NOT (ne)) (IF (east) (s) (n))))

(OR (NOT (IF (nw) (east) (s)))

(AND (IF (w) (sw) (1))

(OR (sw) (nw)))))

(OR (NOT (IF (OR (n) (w))

(OR (0) (se))

(OR (1) (east))))

(OR (AND (OR (1) (ne))


(AND (nw) (east)))

(IF (NOT (west))

(AND (west) (east))

(IF (1) (north) (W)))))))

Лучшая программа второго поколения набрала 117 очков пригодности.


Программа и два ее прогона представлены на рисунке 6. Программа меньше
чем лучшая программа нулевого поколения, но она застревает в нижнем
левом углу.

Рисунок 6. Лучшая программа во втором


поколении.

(NOT (AND (IF (ne)

(IF (se) (south) (east))

(north))

(NOT (NOT (e)))))

В шестом поколении, представление


лучшей программы улучшилось до 163. Лучшая программа идеально следует
вдоль стены, но по-прежнему застревает в верхнем правом углу, как показано
на рисунке 7.

Наконец, в 10-м поколении, процесс обучения остановился. Идеальная


программа и два ее прогона показаны на рисунке 8. Программа идет на юг,
пока не дойдет до стены, и начинает ходить вдоль нее по часовой стрелке.

Рисунок 7. Лучшая программа в поколение 6.

(IF (AND (NOT (ne))

(IF (e) (s) (nw)))

(OR (IF (1) (e) (south))

(IF (north) (east) (nw)))

(IF (OR (AND (0) (north))

(AND (e) (IF (e)

(IF (se) (south) (east))


(north))))

(AND (e)

(NOT (IF (s) (sw) (e))))

(OR (OR (AND (nw) (east))

(west))

(nw))))

Рисунок 8. Лучшая программа в поколении 10.

(IF (IF (IF (0) (ne))

(oR (se) (east))

(IF (OR (AND (e) (0))

(sw))

(OR (sw) (0))

(AND (NOT (NOT (AND (s)


(se))))

(se))))

(IF (w)

(OR (north)

(NOT (NOT (s))))

(west))

(NOT (NOT (NOT (AND (IF (NOT (south))

(se)

(w))

(NOT (n)))))))
На рисунке 9 показана кривая приспособленности лучших программ каждого
поколения. Заметим, что прогресс (хотя часто и не значительно)
увеличивается от поколения к поколению.

Рисунок 9. Зависимость значения приспособленности от числа поколений.

2.3. Замечание о применении метода генетического программирования


В самом простом случае ГП применяется для поиска уравнения регрессии,
поиска наилучшего пути, оптимизации алгоритмов, программирования
абстрактных агентов и физически реальных роботов. Помимо этого,
генетическое программирование было успешно применено в таких областях
как:

 управление космическим аппаратом,

 молекулярная биология,

 синтез электрических схем,

 клеточные автоматы,

 автоматизированное программирование много-агентных систем,


 эволюция ассемблерного кода и многих других.

Следует отметить, что поскольку весь процесс эволюции является


стохастическим, то полное обучение робота сильно зависит от случайностей.
В частности, гуляющий вдоль стены робот в одном случае обучался в 43-ем
поколении, в другом случае в 10-ом, а в третьем случае даже за 100
поколений не смог обучиться. В этой связи очень актуальна проблема
параллельно-распределенного расчета популяций.