Я хочу сделать оптимизатор накопленных 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 (так что ссылки оттуда ).