Мой пример кода, связанный ниже, состоит всего из двух файлов / нескольких сотен строк Python, включая библиотеку GA. Он обучает трехслойный автоматический кодер на MNIST, используя GA.
https://github.com/patniemeyer/ga-autoencoder
Код работает, но по сравнению с обратным распространением невероятно медленный. В некоторых статьях говорится об успехе в обучении сетей с миллионами свободных параметров и достижении результатов всего за несколько поколений, однако моя (сравнительно небольшая, 200 тыс. Параметров) сеть сходится крайне медленно. С обучающим набором, ограниченным только сотней изображений, я видел, что он продолжает (медленный) прогресс после 50 тысяч поколений.
Вещи, которые я попробовал / усвоил:
- Кроссовер, похоже, не помогает, так что я только что максимизировал мутацию.
- Я вычел среднее изображение MNIST из входных пакетов, поскольку алгоритму всегда, кажется, нужно находить среднее изображение (огромные локальные минимумы), прежде чем проводить различие между цифрами.
- Я заверил, что всегда доступны небольшие однослойные мутации с одним значением, чтобы он никогда не застрял полностью.
- Я пытался убедиться, что моя инициализация веса имеет распределение, похожее на то, что я знаю, чтобы получить приличные конечные результаты. (Но даже если я в замешательстве, это может занять больше времени, не так ли?)
- Я пытался поэкспериментировать с «безопасными мутациями», основывая величину мутации на градиенте выхода по отношению к весам, но я не увидел каких-либо улучшений в простых тестах и сдался (возможно, преждевременно). Несмотря на это, я бы предпочел не зависеть от возможности рассчитывать градиенты - вот почему я использую GA! :)
- Я экспериментировал с оболочкой pytorch weight_norm (), которая разделяет направление и величину тензора веса и делает их параметрами слоя: я думал, что, если я дико отключен в инициализации, возможно, это даст GA больше рычагов на Это. У меня действительно были большие надежды, что это поможет, но опять же, либо я делаю это неправильно, либо улучшения не было.
Мне известно, что я могу улучшить производительность времени выполнения GA с помощью распараллеливания и уменьшить объем памяти, сохраняя только начальные значения для мутаций и т. Д. Сейчас я просто пытаюсь отточить алгоритм и посмотрите некоторые результаты, прежде чем тратить больше времени на настройку производительности.
Любые предложения приветствуются. Спасибо!
EDIT:
Я обновил свой код вторым подходом, как описано в этой статье: https://arxiv.org/pdf/1703.03864.pdf
В отличие от «классического» алгоритма, который я описал выше, в этой версии используется взвешенная по фитнесу сумма всей совокупности (больше работает как оценка градиента в фитнес-пространстве). Этот второй алгоритм намного быстрее, хотя у меня все еще возникают проблемы с его сходимостью, когда я увеличиваю объем данных за пределы игрушечного образца. Любые предложения по улучшению будут приветствоваться.
РЕДАКТИРОВАТЬ 2:
Увеличение численности населения помогло. Я также добавил небольшое снижение веса и использую ADAM (https://arxiv.org/abs/1412.6980), чтобы сгладить градиент перед добавлением его к текущим весам. Я также уменьшаю скорость обучения, когда достигаем плато прогресса. Сочетание этих выступать несколько лучше.