machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Введение в PonyGE2 для грамматической эволюции

Дата публикации Jul 5, 2017

Grammatic Evolution - это мощный метод оптимизации алгоритма. Учитывая целевую функцию и пространство поиска (грамматику), можно использовать эволюционные вычислительные методы, чтобы развить алгоритм для оптимального (или, по крайней мере, эффективного) максимизации целевой функции.

PonyGE2это реализация Python3, которая делает GE простым. В этом пошаговом руководстве обсуждаются плюсы и минусы GE и приводится пример того, как развивать свои собственные алгоритмы с GE. Документ, полностью описывающий работу PonyGE2, можно найтиВот,

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


Грамматическая Эволюция

Метод был впервые предложенДоктор Майкл О'Нил(paywall) в 2001 году как способ применения эволюционных вычислительных методов к задачам с формальной грамматической структурой, таким как алгоритмы.

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

  1. Выучить словарный запас
  2. Выучить грамматику

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

Итак, как мы можем преподавать грамматику компьютерам? И как эти слова используются в эволюционной оптимизации?

Процесс работает примерно так:

  1. Определить представление грамматики Бэкуса-Наура (BNF);
  2. Произвольно генерировать линейные хромосомы для кодирования информации;
  3. Оцените пригодность хромосом, сопоставив грамматику с хромосомой и проверив соответствие функции пригодности;
  4. Используйте генетические операторы, такие как кроссовер, мутация и репродукция, чтобы генерировать хромосомы следующего поколения;
  5. Повторите шаги 3 и 4 для определенного количества поколений.

Бакус Наур Форма

Грамматика BNF - это способ написания грамматики, понятной для компьютеров (без контекста). В Python это представлено кортежем, содержащим 4 набора:

  • T: Терминал Set
  • N: нетерминальный набор
  • P: набор правил производства
  • S: Начальный символ (который является членом N).

Это, вероятно, не проясняет ситуацию, но это хорошо иметь в виду. Давайте посмотрим на пример:

T = {+, -, /, *, x, y}

Таким образом, набор терминалов - это набор всех операторов и переменных, которые вы хотите использовать в своей программе.

N = {<e>, <o>, <v>}

Нетерминальный набор - это набор всех производственных операций, которые может выполнять программа. В этой ситуации,<e>это выражение,<o>является оператором, и<v>переменная

Pтогда свод правил производства:

<e> ::= <e><o><e> | <v>
<o> ::= + | - | / | *
<v> ::= x | y

Обратите внимание, что все записи вPзаписи либоTилиN, Трубный оператор|представляетor, Итак, когда<e>встречается в хромосоме, либо заменяется<e><o><e>, или<v>и аналогично для<o>а также<v>,

Наконец, начальный символ:

S = <e>

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

Хромосомы

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

Итак, для нашего примера, давайте назовем нашу хромосому:

C: [4, 15, 75, 8, 41, 12]

Отображение хромосомы в грамматику

Теперь все идет вместе. Помните, что наш начальный символ был:

<e>

Теперь, в соответствии с нашими правилами производстваP, когда<e>встречается, либо заменяется<e><o><e>или<v>, Но как мы узнаем, какой? Ну, хромосома говорит нам. Первое значение хромосомы4, и здесь2варианты для<e>в правилах производства.4 mod 2является0поэтому мы берем0-ой (с нулевым индексом, так что на самом деле1-я запись) опция из правил производства,<e><o><e>,

Так что теперь наше выражение расширилось до<e><o><e>и мы оцениваем первую запись<e>(поскольку он не является членом набора терминалов, мы продолжаем оценивать каждую запись до тех пор, пока она не будет заменена членом набора терминалов).

Мы знаем, что есть2варианты для<e>в правилах производства, поэтому мы берем 2-ю запись в хромосоме,15, а также15 mod 2дает1поэтому мы берем 1-й (нулевой индекс, то есть 2-й элемент) вариант из правил производства,<v>

Мы продолжаем со следующими шагами:

  • Полное выражение:<v><o><e>
    Текущее выражение:<v>
    Количество<v>варианты в грамматике:2
    Значение хромосомы:75
    75 mod 2 = 1
    замещать<v>сy
  • Полное выражение:y <o><e>
    Текущее выражение:<o>
    Количество<o>варианты в грамматике:4
    Значение хромосомы:8
    8 mod 4 = 0
    замещать<o>с+
  • Полное выражение:y + <e>
    Текущее выражение:<e>
    Количество<e>варианты в грамматике:2
    Значение хромосомы:41
    41 mod 2 = 1
    замещать<e>с<v>
  • Полное выражение:y + <v>
    Текущее выражение:<v>
    Количество<v>варианты в грамматике:2
    Значение хромосомы:12
    12 mod 2 = 0
    замещать<v>сx

Окончательное выражение:y + x

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

Оценка фитнес-функции

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

Это продолжается для заданного пользователем числа поколений, после чего вам возвращается наиболее эффективный (лучший результат по фитнес-функции) алгоритм.


Анализ GE

Теперь, когда вы (надеюсь) немного лучше понимаете, что включает в себя грамматическая эволюция, вы можете спросить, почему это так хорошо?

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

Во-вторых, поскольку грамматика написана вами, вы можете легко закодировать знание предметной области в функцию. Вы можете много слышать об этом и спросить: «Что это на самом деле значит?» (Я знаю, что знаю). Вот некоторые примеры:

  • Разрешите доступ ко всей имеющейся у вас информации, независимо от того, полезна ли она. Это может быть достигнуто с помощью<v>Выражение в грамматике и включите все переменные, которые вы хотите.
  • Сделайте программу настолько сложной или простой, насколько это необходимо. Включая множество вариантов в<e>(включая дублированные опции для изменения вероятности выбора конкретного оператора) позволяет легко манипулировать сложностью развитой программы.
  • Определите уровень точности констант, установив<n> ::= 0|1|2|3|4|5|6|7|8|9а потом<const> ::= <n><n><n>.<n><n><n>установить константы от 0 до 999 с точностью до 3 знаков после запятой.
  • Функции включения с выражениями include<fn>(<e>)а также<fn> ::= sin | max

Это все довольно круто, но у GE есть некоторые недостатки. Прежде всего, как упоминалось выше, длина хромосомы приводит к неправильным программам. Для приведенного выше примера, если от второй до последней записи в хромосоме было 42 вместо 41,<e>был бы заменен<e><o><e>, но без данных хромосомы, чтобы оценить эти выражения. Поскольку эта хромосома недействительна, ее нельзя сравнить с функцией пригодности. Таким образом, хотя хромосома может содержать хорошее решение, оно никогда не будет известно.

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

Однако, вероятно, самый большой недостаток заключается в том, что грамматика должна быть построена очень тщательно, и есть немного искусства для построения соответствующих грамматик и функций пригодности для задачи. Кроме того, «большие» грамматики могут развиваться очень долго. Грамматика, включающая одноуровневые циклы for, если операторы, функции списка и словарные операции могут развиваться более 12 часов. Надеюсь, это улучшится в будущем, но главное - не дать Grammatic Evolution заменить замену оптимизаторам человеческого кода…

Так что теперь, надеюсь, у вас есть немного больше понимания того, как Grammatic Evolution, мы можем попробовать реализовать простой пример в PonyGE2.


PonyGE2

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

Лучший способ изучить пакет - проработать пример. Мы попытаемся развить функцию, чтобы найти максимальное значение в списке. Это легко достигается в Python сmax()или функционально:

for val in list:
if val >= current_max:
current_max = val

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

Весь мой код для этих примеров содержится наhttps: // GitHub ком / Padam-0 / NC-GA

Есть множество примеров вPonyGE2/src/fitnessи, чтобы запустить свой собственный, создайте файл с именемmax_in_list.pyв этой папке со структурой что-то вроде этого:

from fitness.base_ff_classes.base_ff import base_ff
import random
import timeclass max_in_list(base_ff):
def __init__(self):
# Initialise base fitness function class.
super().__init__() def evaluate(self, ind, **kwargs):
p = ind.phenotype print("\n" + p) fitness = 0 for trial in range(50):
self.test_list = generate_list()
m = max(self.test_list) d = {'test_list': self.test_list} try:
t0 = time.time()
exec(p, d)
t1 = time.time() guess = d['return_val'] fitness += len(p) v = abs(m - guess)
if v <= 10**6:
fitness += v
else:
fitness = self.default_fitness
break if t1 - t0 < 10:
fitness = self.default_fitness
break
else:
fitness += (t1 - t0) * 1000 except:
fitness = self.default_fitness
break return fitness
def generate_list():
return [random.randint(0, round(random.random() * 90 + 10, 0)) for i in range(9)]

Давайте шаг за шагом пройдемся по нему.

Строки 1–3:

  • Импорт.base-ffэто класс, от которого мы унаследуем, random используется для генерации случайного списка и время для отслеживания времени выполнения

Строка 5:

  • Определить класс,max_in_listнаследуя отbase_ff, Это должно иметь то же имя, что и файл, в котором вы работаете (которыйmax_in_list.pyв этом случае).

Строка 6–9:

  • Информация об инициализации экземпляра для класса.

Строка 10:

  • Создайтеevaluateфункция с тремя параметрами, self, ind и kwargs.

До этого момента это стандартно для каждой фитнес-функции. Что будет дальше, не зависит от каждого разрабатываемого алгоритма.

Строка 11–13:

  • Возвращает текущий алгоритм из эволюции какp, Мы можем напечатать это в командной строке (как мы делаем в строке 13) и увидеть это.

Строка 15:

  • Инициализировать пригодность к0

Строка 17:

  • Установите цикл for для запуска 50 раз. Если мы этого не сделаем, каждый алгоритм будет работать в том же «случайном» списке, и может развить такую ​​строку, какm=49который затем возвращается.49может оказаться в этом списке и максимальное значение, поэтому компьютер считает, что нашел идеальный алгоритм. Коротко, быстро и правильно! Но подходите к этому одному примеру. В любом другом списке, где49не в нем (или не в максимальном значении), алгоритм будет неверным. Таким образом, мы даем фитнес-функции 50 списков для просмотра, все с различными значениями (и действительно максимально возможными значениями), чтобы избежать переобучения.

Строка 18:

  • Создать случайный списокself.test_listиз функцииgenerate_list()
  • Переходя к последним нескольким строкам, эта функция генерирует 10 случайных целых чисел между0и некоторые числа от 10 до 100. Лучше всего избегать переоснащения.

Строка 19:

  • Найти максимум текущего списка, который используется. Это важно сделать здесь, а не после того, как алгоритм был выполнен, так как список может измениться во время выполнения (если операции со списками были включены в грамматику), поэтому верный результат может быть не возвращен.
  • В этот момент вы можете (правильно) спросить, какой смысл делать все это, если у нас уже есть функция для поиска максимального значения списка? Это отличный вопрос, и цель GE - найти потенциально более эффективный способ сделать это. Для простых функций это не стоит, но это хорошее учебное упражнение.

Строка 21:

  • Создать словарьdс одной записьюtest_listкоторый содержит текущий список. Это будет иметь больше смысла, когда мы будем писать грамматику.

Строка 23 / 45–47:

  • Попробуйте / за исключением заявления. Как правило, не стоит использовать открытый оператор Except, так как вы никогда не будете ловить ошибки, но в этом случае все ошибки могут возникать в рамках развитого алгоритма (потому что это просто соединение слов в полуслучайном виде, так что есть ни в коем случае они не будут идеальным кодом), поэтому утверждение оправдано.
  • Если возвращается ошибка, пригодность для этого алгоритма устанавливается по умолчанию (NA), цикл прерывается, и следующий проверенный алгоритм.

Строка 24:

  • Получите время начала.

Строка 25:

  • Выполнить алгоритмpи передать параметры вdтак что они могут быть доступны. Это где алгоритм на самом деле оценивается. Возвращаемое значение записывается в словарьdкакreturn_val(мы определяем это в грамматике).

Строка 26:

  • Получите время окончания.

Строка 28:

  • Получить максимальное значение угадать из текущего алгоритма.

Строка 30:

  • Увеличьте текущий показатель пригодности по длине алгоритма. Это чтобы избежать раздувания и ненужных операторов if. Эволюция старается сделать вещи максимально короткими.

Строка 32:

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

Строка 33–37:

  • Существуют некоторые алгоритмы, которые могут выдавать совершенно негабаритные догадки, которые могут привести к сбою в эволюции, поэтому лучше сохранить оператор if, чтобы проверить значение не выше некоторого большого (но не слишком большого) числа, которое никогда не будет выполнимо.
  • Опять же, если эта проверка не удалась, установите пригодность к NA и переходите к следующему алгоритму. В противном случае добавьте разницу между предположением и правильным значением к текущему результату пригодности.

Строка 39–43:

  • Некоторые алгоритмы (с многоуровневыми для циклов илиfor i in range(1000)заявления) займет очень много времени, чтобы оценить. Если это не ожидается, это указывает на ошибку, поэтому рекомендуется использовать оператор if для отлова тех, которые занимают больше времени (в данном случае 10 секунд).
  • Если алгоритм занимает меньше, чем это, время может быть добавлено к оценке пригодности, так что алгоритмы, которые работают быстрее, будут вознаграждены с более низкой пригодностью. Поскольку временная шкала очень мала, рекомендуется увеличить эту часть оценки в 100 или 1000 раз.

Строка 49:

  • Верните фитнес, и все готово!

Это было много, чтобы принять, и некоторые биты могут не иметь смысла, но мы продолжим писать грамматику, и, надеюсь, с полной картиной это будет немного яснее.


грамматика

Это сложная часть, поскольку вы должны быть очень точными и вдумчивыми в том, что пишете. Мы пройдемся по базовой грамматике, необходимой для развития нашей функции max, но расширения грамматики, которые включают дополнительную логику, функции списка и функции словаря, доступны по адресуhttps://github.com/Padam-0/NC-GA,

Еще раз, PonyGE2 предоставляет примеры грамматики в каталоге PonyGE2 / grammars. Создайте свой там (это можно назвать как угодно, но дайте ему расширения.pybnf).

Первая строка содержит начальную точку для программы:

<fc> ::= <deff>{::}<callf>

На английском это говорит:

  • <fc>является начальным символом, который содержит одну опцию:<deff>с последующим переводом строки ({::}представляет новую строку,{:является отступом (табуляция или 4 пробела) и:}закрывает отступ), затем<callf>,

В следующей строке мы определим<deff>:

<deff> ::= def fun(li):{:m = 0{::}<code>{::}return m:}

Это немного больше похоже на Python. Мы можем видеть, что у нас есть определение функции функции под названиемfun()с одним аргументомli,

Далее мы открываем отступ (как требует Python), инициализируем нашу переменнуюm=0, начните новую строку, напишите<code>, начать новую строку, вернутьm, затем закройте отступ.

Опять же, есть только один вариант<deff>так что это обязательно будет написано. Следующий,<callf>:

<callf> ::= return_val = fun(test_list)

Опять же, это больше похоже на Python. И только один вариант, поэтому независимо от хромосомы наш алгоритм всегда будет выглядеть примерно так:

def fun(li):
m = 0
<code>
return m
return_val = fun(test_list)

<code>раздел - это место, где происходит эволюция, но в большинстве случаев у нас теперь есть работающая функция. Круто, эй! Это становится круче.

Помните, в нашей фитнес-функции мы дали наш словарьdключ называетсяtest_list? Ну, потому что мы называемexec(p, d)программа может видеть содержимое этого словаряdтак что когда он видитtest_listв алгоритме он заменяет его значением, соответствующимtest_listв словареdили, в нашем случае, случайный список, который мы хотим найти максимум! Круто, теперь у нас есть способ передать данные из нашей фитнес-функции в нашу развитую функцию.

И снова, в нашей фитнес-функции, мы устанавливаемguess = d['return_val']? Ну, оказывается, мы можем не только читатьdмы можем написать в него, и значение возвращается изfun(test_list)передаетсяdкакreturn_valТаким образом, мы можем получить доступ к возвращенному значению развитого алгоритма в функции пригодности, чтобы получить доступ к его пригодности!

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

Что касается остальной части нашей грамматики:

<code> ::= <stmt> | <stmt>{::}<code>

Код - это либо отдельный оператор, либо оператор, за которым следует еще какой-то код в новой строке. Таким образом, мы можем дать себе многострочные функции! Эта рекурсивная природа грамматики очень полезна, и ее будет достаточно много, чтобы мы могли усложнить эволюцию.

<stmt> ::= <var> = <expr> | <for> | <if>

Затем оператор либо присваивает выражение переменной, циклу for или оператору if. Давайте посмотрим на это в обратном порядке:

<if> ::= if <cond>:<if-opt>
<if-opt> ::= {:<code>:} | {:<code>:}else:{:<code>:} | {:<code>:}elif <cond>:{:<if-opt>:}<cond> ::= <expr> <c-op> <expr>
<c-op> ::= ">=" | "<=" | ">" | "<"

Таким образом, оператор if принимает условие, а затем параметр. Условие принимает форму выражения, оператора и выражения.

Чтобы сделать это более понятным, стоит обсудить<expr>пометить сейчас:

<expr> ::= <number> | <var> | <expr> <op> <expr>

Таким образом, выражение - это либо число, переменная, либо операция (подробнее обо всем этом позже).

Возвращаясь к нашему утверждению if, наше условие принимает формуif <cond>:который расширяется до:

if <expr> <c-op> <expr>:

Который может затем расшириться до чего-то вроде:

if <var> >= <number>:

И у нас есть заявление, если мы признаем.<if-opt>немного сложнее, так как они должны включатьelifа такжеelseфункциональность, но все они сводятся к выражению if, к условию, а затем к некоторым<code>быть написанным внутри них.

Далее для петель:

<for> ::= for i in <list-var>:{:<fl-code>:}
<fl-stmt> ::= <var> = <expr> | <fl-if>
<fl-code> ::= <fl-stmt> | <fl-stmt>{::}<fl-code>

Таким образом, цикл принимает формуfor i in list:затем создает отступ (в новой строке) для некоторого оператора. Само утверждение может быть просто нашим<stmt>сверху, но это позволило бы использовать вложенные циклы, которые могут экспоненциально увеличить время оценки. Если вы не думаете, что вложенные циклы абсолютно необходимы, избегайте их (это довольно хорошее правило для программирования в целом).

Так что наши<fl-stmt>включает в себя только присвоение переменной и специальный оператор if,<fl-if>:

<fl-if> ::= if <cond>:<fl-if-opt>
<fl-if-opt> ::= {:<fl-code>:} | {:<fl-code>:}else:{:<fl-code>:} | {:<fl-code>:}elif <cond>:{:<fl-if-opt>:}

Это фактически идентично приведенной выше грамматике оператора if, но вместо вызова<code>это вызывает<fl-code>, в основном, чтобы избежать внутри циклов для операторов if внутри циклов. Немного громоздко, но лучше, чем допускать вложенные циклы!

Наконец, присвоение переменной. Мы уже смотрели на<expr>Итак, давайте посмотрим на части, которые составляют его:

<var> ::= m | i
<list-var> ::= li<number> ::= <num><num><num> | <num><num> | <num>
<num> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9<op> ::= + | - | * | / | // | %

Это должно быть довольно просто. Наши переменныеmкоторый мы инициализировали в начале, иiкоторый инициализируется при запуске цикла for. Числа могут быть от 0 до 999, и у нас есть все операторы python (кроме экспоненциальных, которые могут вызвать переполнение целых чисел и целый ряд очень медленных для выполнения алгоритмов Как и для вложенных циклов, включайте их только в случае необходимости).

И хотите верьте, хотите нет, но наша грамматика готова! Давайте посмотрим, как мы можем перейти от<code>тег к нашей последней функции. Хромосома как:

[0, 1, 0, 1, 0, 1, 1, 2, 1, 0, 0, 0, 0, 1, 1]

Намечено, это дает нам:

def fun(li):
for i in li:
if i > m:
m = i
return_val = fun(test_list)

Милая! Теперь, когда у нас есть функция фитнеса и грамматика, как мы можем запустить это с PonyGE2?

Хорошо, если фитнес-функция находится в PonyGE2 / src / fitness (и имеет то же имя файла, что и класс, который она содержит, в данном случае max_in_list), а грамматика в PonyGE2 / грамматиках, мы можем запустить из командной строки:

python ponyge.py --fitness_function max_in_list --grammar_file max_in_list.pybnf

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

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

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

Вы можете установить эти параметры с помощью:

python ponyge.py --fitness_function max_in_list --grammar_file MIL_e2.pybnf --population_size 500 --generations 100

Теперь для простых грамматик достаточно значений этих параметров в диапазоне 100–500, но поскольку грамматики становятся все более сложными, им требуется больше населения и поколений для обеспечения развития достаточного алгоритма. Хороший тест - добавить сложность к вашей грамматике и запустить ее с той же функцией пригодности, что и выше. Если вы получаете функцию, которая находит максимум в списке, вы можете быть уверены, что ваши параметры соответствуют требованиям, а затем переключите ее на другую функцию пригодности для решения проблемы, которую вы пытаетесь решить.

К сожалению, время выполнения увеличивается довольно быстро. Для меня население 2000 и 750 поколений заняло около 6 с половиной часов, и этого было недостаточно для разработки соответствующего алгоритма с приведенной выше грамматикой (но также включающей операции со списком и словарем).

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

Несмотря на это, это поле для наблюдения, так как если мы собираемся научить машины кодировать, есть хорошая ставка, что Grammatic Evolution будет как-то с этим связана.


Другие примеры

Команда вUCD Natural Computing Исследовательская и прикладная группаявляются передовым в этом исследовании, и опубликовали много замечательных работ, показывающих мощь GE (хотя и на суперкомпьютерах). Некоторые включают в себя:


Если вам понравился этот пост, нажмите кнопку ❤, чтобы сообщить об этом своим подписчикам, или сообщите мне свои мысли ниже или в Twitter.@ padams02,

Оригинальная статья

Footer decor

© machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map