В этой статье описаны эксперименты, которые я провел, чтобы заменить стохастический градиентный спуск (SGD) и обратное распространение в моделях глубокого обучения генетическим алгоритмом (GA).

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

Контекст

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

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

Цикл обновления параметров продолжается до тех пор, пока не будет достигнута желаемая точность (не показана на диаграмме).

Я буду использовать W для представления набора параметров модели. Модель глубокого обучения может легко содержать десятки (если не сотни) миллионов параметров. После завершения обучения W сформирует основу обученной модели.

Краткое описание подхода с использованием генетического алгоритма

На следующей диаграмме показано, что SGD заменяется GA, а одиночный W заменяется совокупностью W , который я буду использовать для обозначения [W].

Функция стоимости была удалена и заменена функцией точности, которая обеспечивает функцию соответствия в терминологии GA. Значение пригодности - это приспособленность члена популяции с учетом некоторых критериев. Пригодность - это значение от 0 до 1, где 0 соответствует наиболее подходящей форме. Я буду использовать [F] для обозначения пригодности каждого члена [W].

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

Обзор генетических алгоритмов

Существует множество научных и подробных книг по ГА, например, «Генетические алгоритмы в поиске, оптимизации и машинном обучении» Голдберга. Здесь я останусь на (очень) высоком уровне.

Учитывая популяцию [W] и значение пригодности для каждого члена популяции [F], a GA определит состав населения следующего поколения.

[W] следующий = GA ([W ] текущий, [F] текущий)

Простой ГА можно описать как:

  1. Отбор - объединение участников в пары с использованием фитнеса как предвзятости
  2. Комбинирование - объедините выбранные пары для создания следующего поколения. Это также известно как кроссовер, при котором гены родителей перекрещиваются в следующем поколении.
  3. Мутация - перед тем, как высвободить новую популяцию, примените (небольшое количество) случайную мутацию.

Эксперимент

Изначально я начал с простой задачи XOR, чтобы проверить ход GA. ГА действительно довольно быстро пришла к решению. Однако в этой статье я опишу более существенную проблему.

Эксперимент основан на примере TensorFlow MNIST Deep (mnist_deep.py в репозиториях TensorFlow GitHub). Это глубокая сверточная нейронная сеть для распознавания набора рукописных цифр MNIST. Модель содержит десятки миллионов параметров; Я подумал, что это будет хороший не игрушечный пример.

Я перенес все параметры модели (веса и смещения) в переменные TensorFlow, чтобы было легко управлять значениями вне тензоров TensorFlow. Параметры W были загружены в график модели TensorFlow с помощью feed_dict.

Размер популяции параметризован как N. Каждая из начальных N моделей инициализируется с использованием numpy.random.randn (гауссовское распределение со средним значением 0 и дисперсией 1).

Затем для каждого W из [W] вычисляется значение пригодности. Количество запускаемых поколений составляет G (или до тех пор, пока решение не сойдется).

for generation = 1 to G
   for index = 1 to N
       F[index] = session.run(accuracy, feed_dict = W[index])

Процесс вычисления следующего поколения [W]:

Random pairing of [W], biased towards fitter members
Crossover of each pair in [W]
Random mutation of each member of [W]

Кроссовер

Каждый W формируется набором матриц, где каждая матрица представляет собой часть модели машинного обучения (веса и смещения). Даны два члена пары:

Wa -> [a1, a2, a3, ...] # where each a is a matrix
Wb -> [b1, b2, b3, ...] # where each b is a matrix 

Есть много способов пересечь Wa и Wb. Для этого эксперимента я выбрал случайное пересечение элементов в соответствующих матрицах. Например:

mask = random 0 or 1 in shape of a1
mask_inv = opposite of mask
new_a1 = a1 * mask + b1 * mask_inv
new_b1 = b1 * mask + a1 * mask_inv
and so on for (a2,b2), (a3, b3), etc.

Мутация

В качестве гиперпараметра GA существует «количество мутаций», но само количество мутаций варьируется в зависимости от того, насколько близко или далеко текущая сходимость решения. В конце концов, я обнаружил, что мутацию сложно понять и применить.

Полученные результаты

На первой диаграмме показана численность популяции в 200 человек на 300 поколений.

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

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

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

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

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

Выводы и обсуждение

Было бы справедливо сказать, что численность населения в 200 или даже 1000 человек, вероятно, слишком мала для достижения значимых результатов. Возможно, численность населения должна исчисляться миллионами.

Помимо размера популяции, можно рассмотреть еще несколько гиперпараметров. Вот несколько примеров:

  1. Ранжирование и попарный отбор. Насколько предвзяты те, кто занимается физическими упражнениями? В своих экспериментах я повысил эффективность лучших исполнителей, чтобы они имели большее влияние, чем это строго диктуется фитнесом.
  2. Мутация. Сколько мутации? Как это применяется? Меняется ли в зависимости от схождения?
  3. Кроссовер. Как пересекаются две модели? Я выбираю равномерное пересечение с детализацией матрицы. Должен ли более сильный из пары сохранять больше ценностей? Следует ли разрезать матрицы, а затем соединять? Следует ли определять кроссовер при переключении целых матриц?
  4. Размер партии. Я пробовал разные размеры партий, остановившись на размере партии 64.
  5. Переоснащение. Взглянув на прогон на 1000 популяций, можно увидеть, возможно, что результаты обучения улучшаются, тогда как результаты проверки выровнялись до более высокого значения.

Для меня следующие шаги не определены, поскольку выравнивание конвергенции валидации было упорным препятствием, которое нужно преодолеть (по крайней мере, в пределах доступной мне мощности компьютера, MacBook Pro 2018).

Если вы зашли так далеко, благодарим вас за внимание и время, и я надеюсь, вам понравилась статья!