Совет по созданию кастомного оптимизатора tf.keras (optimizer_v2) - PullRequest
1 голос
/ 27 мая 2020

Я хочу сделать оптимизатор накопленных SGD для tf.keras (а не keras автономным). Я нашел несколько реализаций автономных keras накопленных оптимизаторов SGD, включая этот один на pypi. Тем не менее, я использую проект, в котором используется tf.keras. И, как я видел, смешивать их вместе - не лучшая идея.

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

Требуемые методы, которые следует переопределить: - resource_apply_dense (переменная обновления с заданным тензором градиента является плотной) - resource_apply_sparse (переменная обновления с заданным тензором градиента разрежена) - create_slots (если вашему алгоритму оптимизатора требуются дополнительные переменные) - get_config (сериализация оптимизатора, включая все гиперпараметры )

Конечно, только get_config() существует в базовом классе. resource_apply_dense на самом деле _resource_apply_dense, resource_apply_sparse это _resource_apply_sparse, а create_slots даже не существует в базовом классе. В подклассах как SGD в gradient_decent.py, create_slots также существует как _create_slots.

В любом случае, по-видимому, документация не обновляется (в git также есть проблема, связанная с этим, но я не помню ссылку, которая указала на это несоответствие с документацией), но это делает всю процедуру трудно. Например, в SGD мне нужно переопределить метод _resource_apply_dense(), но я не могу понять, где вычисляются градиенты и где они обновляются.

Фактический код приведен ниже:

def _resource_apply_dense(self, grad, var, apply_state=None):
        var_device, var_dtype = var.device, var.dtype.base_dtype
        coefficients = ((apply_state or {}).get((var_device, var_dtype))
                        or self._fallback_apply_state(var_device, var_dtype))

        if self._momentum:
          momentum_var = self.get_slot(var, "momentum")
          return training_ops.resource_apply_keras_momentum(
              var.handle,
            momentum_var.handle,
            coefficients["lr_t"],
            grad,
            coefficients["momentum"],
            use_locking=self._use_locking,
            use_nesterov=self.nesterov)
        else:
            return training_ops.resource_apply_gradient_descent(
                var.handle, coefficients["lr_t"], grad, use_locking=self._use_locking)

, которые, очевидно, полагаются на training_ops.resource_apply_keras_momentum и training_ops.resource_apply_gradient_descent для выполнения фактической работы. Как я могу разделить 2 части, упомянутые в методе minimize() в OptimizerV2, из приведенного выше кода? Это 2 части: _compute_gradients() и apply_gradients().

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

Многие оптимизаторы подклассы, такие как Adam и Adagrad, выделяют и управляют дополнительными переменными, связанными с переменными для обучения. Они называются слотами . У слотов есть имена, и вы можете запросить у оптимизатора имена используемых им слотов.

хотя, если я объявляю оптимизатор Adam и запрашиваю имена слотов, я получаю пустой список (?).

optimizer = Adam(lr=1e-3)    
optimizer.get_slot_names()

[]

Другой сбивающей с толку проблемой является использование частных методов, из-за которых неясно, когда они вызываются и какова их цель. Например, _prepare_local() содержится в SGD и включает строку:

apply_state[(var_device, var_dtype)]["momentum"] = array_ops.identity(self._get_hyper("momentum", var_dtype))

В любом случае проблема в том, что я не знаю, какой именно подход использовать для создания настраиваемого оптимизатора tf.keras. Инструкции, включенные в комментарии, кажутся противоречащими реальным реализованным подклассам, и последние также, похоже, возлагают грязную работу на фактическую функцию C ++, не имея четкого представления о том, как это делается или как (в моем случае) разделить действия (например, градиент расчет и применение). Итак, есть ли какой-нибудь совет, который кто-то может дать, как действовать, и шаги, которые нужно выполнить, чтобы выполнить sh эту (относительно) простую задачу?

Кстати, я использую tf 1.15 (так что ссылки оттуда ).

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