Генерация кода генетическими алгоритмами - PullRequest
30 голосов
/ 20 апреля 2011

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

Мне было интересно, есть ли способ эволюционно создать программу на языке ruby ​​/ python (или на любом другом языке)?

Идея проста:

  1. Создание набора программ
  2. Выполнение генетических операций (выбор колеса рулетки или любой другой выбор), создание новых программ с наследованием от лучших программ и т. Д.
  3. Цикл 2 до тех пор, пока не будет найдена программа, которая будет удовлетворять нашему условию

Но есть еще несколько проблем:

  1. Как будут представлены хромосомы?Например, должна ли одна клетка хромосомы быть одной строкой кода?
  2. Как будут генерироваться хромосомы?Если они будут строками кода, как мы сгенерируем их, чтобы гарантировать их синтаксическую корректность и т. Д .?

Пример программы, которая может быть сгенерирована:

Создать скрипткоторый принимает N чисел в качестве входных данных и возвращает их среднее значение в качестве выходных.

Если бы были какие-либо попытки создать такие алгоритмы, я был бы рад увидеть любые ссылки / источники.

Ответы [ 8 ]

23 голосов
/ 21 апреля 2011

Если вы уверены, что хотите это сделать, вам нужно генетическое программирование , а не генетический алгоритм.GP позволяет развивать древовидные программы.Что бы вы сделали, это дали бы ему кучу примитивных операций (while ($ register), read ($ register), increment ($ register), decment ($ register), деление ($ result $ Numberrator $ denominator), печать, progn2 (это GP говорит для «выполнить две команды последовательно»)).

Вы можете создать что-то вроде этого:

progn2(
  progn2(
    read($1)
    while($1
      progn2(
        while($1
          progn2( #add the input to the total
            increment($2)
            decrement($1)
          )
        )
        progn2( #increment number of values entered, read again
          increment($3)
          read($1)
        )
      )
    )
  )
  progn2( #calculate result
    divide($1 $2 $3)
    print($1)
  )
)  

Вы будете использовать, как свою функцию пригодности, насколько близкоэто к настоящему решению.И в этом заключается уловка, которую вы все равно должны рассчитать традиционно *.И затем есть что-то, что переводит это в код (ваш язык по вашему выбору).Обратите внимание, что, поскольку у вас есть потенциальный бесконечный цикл, вам придется через некоторое время прервать выполнение (нет способа обойти проблему остановки), и это, вероятно, не будет работать.Чепуха.Также обратите внимание, что мой предоставленный код будет пытаться делить на ноль.

* Есть способы обойти это, но, как правило, не так уж и далеко.

15 голосов
/ 20 апреля 2011

Это можно сделать, но очень плохо работает для большинства видов приложений.

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

К сожалению, правильность программы совершенно не непрерывна. Программа, которая останавливается с ошибкой X в строке A, лучше, чем программа, которая останавливается с ошибкой Y в строке B? Ваша программа может находиться на расстоянии одного символа от правильной и все равно прерываться с ошибкой, в то время как программа, которая возвращает постоянный жестко закодированный результат, может, по крайней мере, пройти один тест.

И это даже не касается вопроса о том, что сам код не является непрерывным при модификациях ...

9 голосов
/ 25 апреля 2011

Ну, это очень возможно, и @Jivlain правильно указывает в своем (хорошем) ответе, что вы ищете генетическое программирование (а не простые генетические алгоритмы).

Генетическое программирование - область, которая еще не достигла широкой аудитории, частично из-за некоторых осложнений, на которые указывает @MichaelBorgwardt в своем ответе. Но это просто осложнения , это далеко от истины, что это невозможно сделать. Исследования по этой теме ведутся уже более 20 лет.

Андре Коза является одним из ведущих исследователей в этой области (взгляните на его работу 1992 ), и он продемонстрировал уже в 1996 , как генетическое программирование может в некоторых случаях превзойти наивное GA на некоторых классических вычислительных задачах (таких как развивающиеся программы для синхронизации Cellular Automata).

Вот хорошее Учебное пособие по генетическому программированию от Козы и Поли от 2003 года.

Для недавнего ознакомления вы могли бы взглянуть на Полевое руководство по генетическому программированию (2008).

4 голосов
/ 02 марта 2015

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

  • PushGP - разработанные с целью развития модульных функций, таких как использование программистов-людей, программы в этой системе хранят все переменные и код в разных стеках(по одному для каждого типа переменной).Программы пишутся путем выталкивания и извлечения команд и данных из стеков.
  • FINCH - система, которая развивает Java-байт-код.Это было очень полезно для развития игровых агентов.
  • Различные алгоритмы начали развивать код C ++, часто с шагом, на котором исправляются ошибки компилятора.Это имело смешанные, но не совсем бесперспективные результаты. Вот пример .
  • Avida - система, в которой агенты развивают программы (в основном, задачи логической логики), используя очень простой ассемблерный код.Основан на старшем (и менее универсальном) Tierra .
1 голос
/ 20 апреля 2011

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

Например, поскольку любой язык Ruby может быть определен в виде текстовой строки, вы можете просто генерировать текстовые строки случайным образом и оптимизировать их. Лучше было бы генерировать только легальные программы на Ruby. Однако это также заняло бы вечность.

Если бы вы пытались построить программу сортировки, и у вас были операции высокого уровня, такие как «своп», «перемещение» и т. Д., То у вас был бы гораздо более высокий шанс на успех.

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

0 голосов
/ 21 апреля 2011

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

0 голосов
/ 20 апреля 2011

Удачи с этим.

Конечно, вы можете написать «мутационную» программу, которая читает программу и случайным образом добавляет, удаляет или изменяет некоторое количество символов. Затем вы можете скомпилировать результат и посмотреть, лучше ли результат, чем оригинальная программа. (Однако мы определяем и измеряем «лучше».) Конечно, в 99,9% случаев результатом будут ошибки компиляции: синтаксические ошибки, неопределенные переменные и т. Д. И, конечно, большая часть остальных будет крайне неправильной.

Попробуйте несколько очень простых задач. Скажем, начните с программы, которая читает два числа, складывает их вместе и выводит сумму. Допустим, целью является программа, которая читает три числа и вычисляет сумму. Насколько долгой и сложной будет такая программа, конечно, зависит от языка. Допустим, у нас есть очень высокоуровневый язык, который позволяет нам читать или писать числа всего одной строкой кода. Тогда стартовая программа всего 4 строки:

read x
read y
total=x+y
write total

Самая простая программа для достижения желаемой цели будет выглядеть примерно так:

read x
read y
read z
total=x+y+z
write total

Таким образом, при случайной мутации мы должны добавить «read z» и «+ z», всего 9 символов, включая пробел и новую строку. Давайте упростим нашу программу мутации и скажем, что она всегда вставляет ровно 9 случайных символов, что они гарантированно находятся в нужных местах, и что она выбирает из набора символов всего 26 букв плюс 10 цифр плюс 14 специальных символов = 50 символов. Каковы шансы, что он выберет правильные 9 символов? 1 в 50 ^ 9 = 1 в 2.0e15. (Хорошо, программа работала бы, если бы вместо «read z» и «+ z» она вставила «read w» и «+ w», но тогда я упрощаю это, предполагая, что она волшебным образом вставляет точно правильное количество символов и всегда вставляет их в нужных местах. Так что я думаю, что эта оценка все еще великодушно.)

1 в 2.0e15 - довольно малая вероятность. Даже если программа запускается тысячу раз в секунду, и вы можете быстро протестировать вывод, шанс все равно составляет всего 1 на 2,0e12 в секунду или 1 на 5,4e8 в час, 1 на 2,3e7 в день. Продолжайте работать в течение года, и шанс на успех по-прежнему составляет только 1 из 62 000.

Даже умеренно компетентный программист должен быть в состоянии сделать такое изменение за десять минут?

Обратите внимание, что изменения должны входить как минимум в "правильные" пакеты. То есть, если мутация генерирует «reax z», это только один символ от «read z», но она все равно будет приводить к ошибкам компиляции и, таким образом, потерпит неудачу.

Аналогично, добавление «read z», но изменение вычисления на «total = x + y + w» не сработает. В зависимости от языка вы либо получите ошибки для неопределенной переменной, либо, в лучшем случае, она будет иметь некоторое значение по умолчанию, например ноль, и даст неверные результаты.

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

И это очень тривиальная программа на очень простом языке. Большинство программ - это сотни или тысячи строк, которые должны работать вместе. Шансы против любого случайного процесса написания работающей программы астрономические.

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

0 голосов
/ 20 апреля 2011

Самым большим преимуществом генетических алгоритмов, как вы говорите, является то, что они очень простые .У них нет лучшей производительности или математического фона, но даже если вы не знаете, как решить вашу проблему, , пока вы можете определить ее как проблему оптимизации , вы сможете превратить ее вGA.

Программы на самом деле не подходят для GA именно потому, что код не является хорошим хромосомным материалом.Я видел кого-то, кто делал что-то похожее с (более простым) машинным кодом вместо Python (хотя это была скорее симуляция экосистемы, чем GA как таковая), и вам может повезти, если вы кодифицируете свои программы с использованием автоматов / LISP или чего-то подобногочто.


С другой стороны, учитывая, насколько привлекательны ГА и как в основном все, кто смотрит на них, задают тот же вопрос, я почти уверен, что уже есть люди, которые пробовали это где-то - я простопонятия не имею, удалось ли кому-либо из них.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...