Правило обновления можно воспринимать как геном клетки и он у всех клеток будет общим. Правило работает (и клетки живут) на двумерном поле, по факту на тензоре размерности `[height, width, 16]`. Мы хотим, чтобы на клетку влияло только близкое окружение, так что у правила будет небольшое рецептивное поле, скажем 3x3, с самой клеткой в середине (как и у игры жизнь). Это можно задать операцией свёртки. Каждая клетка “смотрит” на своё ближайшее окружение (через свёртку размером 3x3). Авторы не стали делать эту свёртку обучаемой, а решили выбрать заранее заданные фильтры Собеля, горизонтальный и вертикальный. Они используются для выделения границ, то есть по сути считают производные по направлениям. Авторы исходили из логики, что внутри организмов клетки часто ориентируются на химические градиенты для направления развития организма. Итого, на вход правила обновления отправляются 48 чисел: 16 чисел оригинального состояния, и ещё два раза по 16 — градиенты по горизонтали и вертикали. Далее обучаемая часть, которая генерит дельту, добавляемую к исходному состоянию клетки. Обучаемая часть задана двуслойной сетью: `dense-128 -> relu -> dense-16` (на выходе relu нет, так как дельты могут быть и отрицательными). Инициализировано так, чтобы на старте обучения давало ноль и ничего не делало с исходным состоянием. Есть также стохастическое обновление. Обычные KA обновляют все клетки одномоментно, как будто есть глобальная синхронизация. В живых организмах её нет и авторы ослабляют требование синхронизации, считая, что обновления клеток происходят через случайные интервалы времени. Для эмуляции этого процесса генерируется бинарная маска (по превышению рандомом 0.5) и обновляются только клетки с установленной маской. Можно также рассматривать это как поклеточный дропаут. Для моделирования процесса роста организма надо чтобы на обновление влияли только клетки организма (не фона), поэтому все каналы пустых клеток (определяемых по альфа-каналу) устанавливаются в ноль. Пустой считается клетка без зрелых (α>0.1) соседей в окружении 3x3. В целом простые правила. Далее, чтобы обучить на какую-то задачу надо задать лосс-функцию. Эксперименты В первом эксперименте обучают КА расти, то есть достигать целевого изображения, стартуя с одной клетки (seed). Эта клетка инициализирована единицами во всех каналах кроме RGB, затем к ней многократно применяется правило обновления (количество применений сэмплится из диапазона [64, 96]). В конце такого шага считается L2-лосс между целевым изображением и RGBA каналами, по сигналу от этого лосса с помощью градиентного спуска происходит обучение двух dense слоёв в правиле обновления. Правила выучиваются генерить заданные паттерны, но будучи запущенными дольше, чем было во время обучения, начинают портить изображения. Хочется сделать так, что когда изображение создано, оно остаётся. Сделать его своеобразным аттрактором, про это второй эксперимент. По идее для этого можно обучать на большем количестве итераций, периодически применяя лосс. Это требует заметно больше памяти и, понятное дело, дольше. Авторы пошли другим путём. Они стартуют с пула начальных состояний (например, 1024 штуки). Из него сэмплится батч для шага обучения (32 сэмпла), но один сэмпл в батче всегда заменяется на оригинальное начальное состояние, чтобы предотвратить катастрофическое забывание. После шага обучения проитерированные сэмплы заменяют в пуле оригинальные. Это помогает добавить стабильности. Также помогает замена на начальное значение не случайного сэмпла, а сэмпла с худшим лоссом.