具有多个损失函数评估的自定义优化器

时间:2021-01-19 12:35:26

标签: tensorflow machine-learning keras

我想为 TF 模型实现自定义优化算法。 我已阅读以下来源

但是还有很多问题。

  1. 在使用自定义优化器 API 时,似乎不可能在应用梯度步骤之前多次评估损失函数(针对不同的权重设置)。例如,在线性搜索类型的算法中,这是必要的。

  2. 我尝试手动完成所有步骤。

假设我已经像这样设置了我的模型和我的优化问题

from tensorflow.keras import layers
from tensorflow.keras import losses
from tensorflow.keras import models

model = models.Sequential()
model.add(layers.Dense(15, input_dim=10))
model.add(layers.Dense(20))
model.add(layers.Dense(1))

x_train, y_train = get_train_data()
loss = losses.MeanSquaredError()

def val_and_grads(weights):
    model.set_weights(weights)

    with tf.GradientTape() as tape:
        val = loss(y_train, model(x_train))

    grads = tape.gradient(val, model.trainable_variables)

    return val, grads

initial_weights = model.get_weights()
optimal_weigths = my_fancy_optimization_algorithm(val_and_grads, initial_weights)

然而,我的函数 val_and_grads 需要 list 的权重,并从 list 的角度返回 my_fancy_optimization_algorithm 的梯度,这似乎不自然。

我可以像这样扭曲 val_and_grads 以“堆叠”返回的梯度并“拆分”传递的权重

def wrapped_val_and_grad(weights):
    grads = val_and_grads(split_weights(weights))
    return stack_grads(grads)

然而,这似乎非常低效。

无论如何,我不喜欢这种方法,因为我似乎会失去很多周围的 tensorflow 基础设施(在学习期间打印当前的损失函数值和指标,张量板的东西,......)。

>
  1. 我还可以将上述内容打包到自定义模型中,并使用像这样定制的 train_step
def CustomModel(keras.Model):
    def train_step(self, data):
    
        x_train, y_train = data

        def val_and_grads(weights):
            self.set_weights(weights)
        
            with tf.GradientTape() as tape:
                val = loss(y_train, self(x_train))
        
            grads = tape.gradient(val, self.trainable_variables)
            return val, grads

        trainable_vars = self.trainable_variables

        old_weights = self.get_weights()
        update = my_fancy_update_finding_algorithm(val_and_grads, self.get_weights()) # this can do multiple evaluations of the model
        self.set_weights(old_weights) # restore the weights

        self.optimizer.apply_gradients(zip(update, trainable_vars))

在这里,我需要一个随附的自定义优化器,它除了通过添加 update (new_weigths = current_weights + update) 更新当前权重外,什么都不做。

我仍然不确定这是否是最好的方法。

如果有人可以对上面的片段和想法发表评论,请指导我找到我应该考虑的任何其他资源,或者提供新的方法和其他反馈,我会非常高兴。

谢谢大家。

弗兰兹


编辑: 遗憾的是,到目前为止我没有得到任何回应。也许我的问题不够具体。作为第一个较小的问题: 鉴于第一个列表中的 modelval_and_grads。我如何有效地计算整个梯度的范数?到目前为止我所做的是

import numpy as np
_, grads = val_and_grad(model.get_weights())
norm_grads = np.linalg.norm(np.concatenate([grad.numpy().flatten() for grad in grad]))

这肯定不是“正确”的方式。

0 个答案:

没有答案